local _ENV = hf_setenv('zjhctable',true)

------------------------------------------------------------------------
--炸金花房间服务
local skynet = require "skynet"
local zjh = require "zhajinhua.czjh"
local utils = require "utils"
local proxypack = require "proxypack"
local msgdef = require "msgdef"
local pb = require 'protobuf'
local cjson = require "cjson"
local server_def = require "server_def"
local util = require "util"
local table_def = require "table_def"
local sharedata = require "skynet.sharedata"
local offline_op = require "offline_op"
local error_code = require "error_code"
local reason = require "reason"
local cocall = require "cocall"
local game_robot = require "zhajinhua.zjh_robot"
local constant = require "constant"
local select_server = require("router_selector")
local system_store = require "system_store"
local game_def = require "game_def"
local friendroomdata = require "friendroomdata"
local events = require "events"
local expand = require("expand") --老游戏功能拓展

local table_insert = table.insert
local table_remove = table.remove
local table_sort   = table.sort
local table_unpack = table.unpack
local math_floor = math.floor
local string_format = string.format
local math_random = math.random
local math_abs = math.abs
local math_min = math.min

--------------------玩家进场状态---------------------
local PLAYER_STATUS_READY = 1
local PLAYER_STATUS_NOREADY = 2
local PLAYER_STATUS_PLAYING = 3

-------------------管理---------------------
local REGISTER_CLIENT_FD = 0
local ROBOT_CLIENT_FD = -1
local OFFLINE_CLIENT_FD = -2

------------------解散管理------------------------------
local RECYCLEING_TABLE_TIMEOUT = 60

local DISS_REASON_CREATOR = 1
local DISS_REASON_UNSTART_TIME_OUT = 2
local DISS_REASON_TIME_OUT = 3
local DISS_REASON_ROUND_OVER = 4
local DISS_REASON_CLOSE_SERVER = 5

-----------------------游戏状态------------------------
local TABLE_STATUS_REGISTERED = 1 --刚刚注册
local TABLE_STATUS_WAITING_ENTER = 2
local TABLE_STATUS_WAITTING_READY = 3 --等待准备
local TABLE_STATUS_PULL_ROBOT = 4 --拉取机器人状态
local TABLE_STATUS_WAITTING_REST = 5 --游戏开始前有三秒的休息状态
local TABLE_STATUS_CHECK_START = 6 --游戏开始
local TABLE_STATUS_PLAYING = 7 --开始玩游戏
local TABLE_STATUS_GAMEOVER = 8
local TABLE_STATUS_RESTART = 9
local TABLE_STATUS_ANIMATION = 10

-----------------------超时站起------------------
local MAX_TIMEOUT_TIMES = 2
-----------------------站起原因------------------
local STANDUP_NORMAL = 0
local STANDUP_TIMEOOUT = 1
local STANDUP_CHANGETABLE = 2
local STANDUP_EXIT = 3
local STANDUP_KICK = 4

-----------------------牌局记录类型-------------------
local RECORD_TYPE_GIVEUP = 1
local RECORD_TYPE_COMPARE = 2
local RECORD_TYPE_LOOK = 3
local RECORD_TYPE_FOLLOW = 4
local RECORD_TYPE_ADD = 5
local RECORD_TYPE_RESULT = 6
local RECORD_TYPE_DIZHU = 7

local ADD_TYPE_JIA = 1
local ADD_TYPE_GEN = 2

local ROUND_TYPE_CURR = 2
local ROUND_TYPE_LAST = 1
-----------------------满轮首次比牌延迟时间-----------------
local MAX_ROUND_COMPARE_DELAY_TIME = 0.5

-------------------桌子服模式-------------------------

local handler = {}
local internal = {}
local load_robot = nil

--机器人类型概率,分别对应：1:看牌型;2:焖牌型;3:土豪型
--local robot_type_rate = {40, 50, 10}

function init(params)
    zjh = params.zjh
    robot_AI = params.robot_AI

    global_configs = nil
    --标记房间所有玩家的clientId 包括观战者的clientId
    table_players = {}
    --管理房间内已经坐下的玩家列表
    player_info_list = {}
    --管理房间内所有玩家状态列表
    player_status_list = {}
    --坐下的玩家的顺序
    ordered_players = {}
    new_banker_uid = nil
    --付费过的玩家列表
    pay_list = {}
    --进入过本房间但是没开过局的玩家列表
    players_never_start = {}

    -----每一局的对战记录--------------
    record_list = {}

    curr_zjh_instance = nil
    --------------------游戏关服管理--------------------
    closing_server = false
    stopping_server = false --停止服务器
    on_matching = false --在匹配中
    is_round_over = false
    recycling_table_start_time = nil
        
    table_info = nil
    creator_uid = nil
    curr_round = nil
    ftable_expiry_time = nil
    ftable_unstart_expiry_time = nil
    waiting_enter_timeout = nil
    ready_timeout = nil --准备状态超时

    curr_status = nil
    curr_locked_uids = {}
    reconnect_timout = {} --重连超时时间
    player_timeout   = {} --玩家超时次数

    --------------------游戏时长管理--------------------
    game_register_time = nil
    game_start_time = 0
    game_over_time = 0
    game_rest_time = 0
    game_animation_time = nil

    robot_manager = {}
    game_update_co = nil

    tablesvr_id = nil
    self_table_type = nil
    self_table_id = nil
    self_password = nil
    this_table_gid = nil
    self_table_pattern = nil
    self_game_type = nil
     --机器人数量标记
    --add_robot_num = 0
    curr_round_need_player = 0
    last_load_robot_time = 0

    award_system_flag = false    --是否从库存2(奖金库存扣钱)，若为true，玩家要从奖金库存拿钱
    control_player_uid = nil        --受控玩家的uid
    control_win = false
    control_lose = false
    is_control_systerm_win = false    --是否控制系统赢

    --enter_robot_map = {}

    op_record_list = {} --保存上一轮和这一轮的操作记录,1:弃牌 2:比牌 3：看牌 4:跟注 5：加注 6:比牌结果
    --触发财神驾到的金额
    caishen_coins_map = {}
    record_pic_player = {} --记录前三局输赢玩家的uid

    is_curr_have_robot = false
    gm_store_coins_add = 0

    system_result_type = 0 --系统控制类型
    gm_control_uid     = 0 --gm控制玩家uid
    system_win_lose = 0 --系统输赢
    hf_set_sentinel_end(_ENV)   
end

local function load_config()
    local attr = {}
    global_configs = nil
    global_configs = setmetatable({},{
        __index = function(t,k) 
            if attr[k] then
                return attr[k]
            else
                local v = sharedata.deepcopy(k)
                attr[k] = v
                return v
            end
        end
    })
    _G.global_configs = global_configs
end

local function send_to_gateway(uid,client_fd,...)
    if not client_fd or client_fd <= 0 then
        return
    end
    return utils.send_to_gateway(0,uid,client_fd,...)
end

local function notify_others(action,excepted_uid,msg)
    --先广播给桌子上的人
    for uid, fd in pairs(table_players) do
        if uid ~= excepted_uid then
            send_to_gateway(uid,fd,action,msg)
        end
    end
end

local function notify_all(action,msg)
    return notify_others(action,nil,msg)
end

--把输赢发送到好友服(平台游戏概况)
local function sendLoseWinToFriendServer(system_lose_win)  
    if system_lose_win == 0 then return end             
    R().friendsvr(1):send('.info_mgr', 'set_room_summary', self_table_type, {table_type = self_table_type, lose_win = system_lose_win})
end  

local function is_robot(uid)
    return robot_manager[uid] and true
end

local function is_banker(uid)
    return new_banker_uid == uid
end

local function set_on_match()
    on_matching = true
end

local function unset_on_match()
    on_matching = false
end

local function is_on_match()
    return on_matching
end

local function add_record(record_type,uid,target_uid,winner_uid,win_coins)
    local curr_round_record = op_record_list[curr_round]
    if not curr_round_record then
        curr_round_record = {}
        op_record_list[curr_round] = curr_round_record
    end

    local name,target_name,winner_name
    if uid and player_info_list[uid] then
        -- name = player_info_list[uid].name
        name = ""..uid
    end

    if target_uid and player_info_list[target_uid] then
        -- target_name = player_info_list[target_uid].name
        target_name = ""..target_uid
    end

    if winner_uid and player_info_list[winner_uid] then
        -- winner_name = player_info_list[winner_uid].name
        winner_name = ""..winner_uid
    end
    dbglog("_________NTF_OP_INFO________", name, target_name, winner_name)
    table_insert(curr_round_record,
    {record_type = record_type,name = name,uid = uid,target_name = target_name,winner_name = winner_name,coins = win_coins})
    notify_all("zhajinhua.NTF_OP_INFO",{op_info=
    {record_type = record_type,name = name,uid = uid,target_name = target_name,winner_name = winner_name,coins = win_coins}})
end


local function check_del_record()
    for round,list in pairs(op_record_list) do
        if curr_round > round + 1 then
            op_record_list[round] = nil
        end
    end
end
--[[
    获取当前桌上的玩家数量
]]
local function get_player_num()
    local player_num = 0
    for _,uid in pairs(ordered_players) do
        player_num = player_num + 1
    end
    return player_num
end

local function get_robot_num()
    local robot_num = 0
    for _,uid in pairs(ordered_players) do
        if is_robot(uid) then
            robot_num = robot_num + 1
        end
    end
    return robot_num
end

local function get_human_num()
    local human_num = 0
    for _,uid in pairs(ordered_players) do
        if not is_robot(uid) then
            human_num = human_num + 1
        end
    end
    return human_num
end

local function get_all_player_num()
    local num = 0
    for _,v in pairs(player_info_list) do
        num = num + 1
    end

    return num
end

local function get_player_state(uid)
    return player_status_list[uid]
end

local function get_player_online(uid)
    --在线状态
    if table_players[uid] and table_players[uid] == OFFLINE_CLIENT_FD then
        return false
    end
    return true
end

local function make_player_info(uid)
    local player_info = player_info_list[uid]

    local player = {
        uid = uid,
        name = player_info.name,
        position = player_info.position,
        coins = player_info.coins,
        icon = player_info.icon,
        sex = player_info.sex,
        vip_level = player_info.vip_level,
        icon_border = player_info.icon_border,
        state = get_player_state(uid),
        online = get_player_online(uid),
    }
    return player
end

local function trigger_event(action,...)
    for _,AIobj in pairs(robot_manager) do
        local f = AIobj[action]
        if f then
            f(AIobj,...)
        end
    end
end

local function get_extra_bill_info(uid)
    local t = {game_type=self_game_type,table_type=self_table_type}
    local player_info = player_info_list[uid]
    if not player_info then
        return t
    end

    t.client_version = player_info.client_version
    t.channel = player_info.channel
    t.cur_channel = player_info.cur_channel
    t.device_id = player_info.device_id
    t.device_brand = player_info.device_brand
    t.os_system = player_info.os_system
    t.platform = player_info.platform

    return t
end

-- local function get_robot_weight_list()
--     local list = {}
--     for uid,_ in pairs(player_info_list) do
--         if is_robot(uid) then
--             local weight = curr_zjh_instance:get_robot_weight(uid) or 0
--             table_insert(list,{uid = uid, weight = weight})
--         end
--     end
--    -- print("=========get_robot_weight_list===",tostring_r(list))
--     return list
-- end

local function send_next_player_operate_status()
    if not curr_zjh_instance then
        return false
    end

    local next_player_id = curr_zjh_instance:get_next_player_uid()
    if not table_players[next_player_id] then
        return false
    end

     --切换下手的时候通知下家玩家的操作按钮
    --print(next_player_id,'send_next_player_operate_status')
    local player_info = player_info_list[next_player_id]
    if player_info then
        local buttons_status = curr_zjh_instance:get_buttons_status(next_player_id,player_info.coins,is_robot(next_player_id),player_info_list)
        if is_robot(next_player_id) then
            robot_manager[next_player_id]['ntf_player_operate_status'](robot_manager[next_player_id],{buttons_status = buttons_status})
            --notify_all("zhajinhua.NTF_ROBOT_WEIGHT",{weight_list=get_robot_weight_list()})
        else
            send_to_gateway(next_player_id,table_players[next_player_id],'zhajinhua.NTF_PLAYER_OPERATE_STATUS',{uid = next_player_id,buttons_status = buttons_status})
        end
        return true
    end

    return false
end

local function send_self_operate_status(uid)
    if not curr_zjh_instance then
        return false
    end

    local player_info = player_info_list[uid]
    if player_info then
        local buttons_status = curr_zjh_instance:get_buttons_status(uid,player_info.coins,is_robot(uid),player_info_list)
        if is_robot(uid) then
            robot_manager[uid]['ntf_player_operate_status'](robot_manager[uid],{buttons_status = buttons_status})
            --notify_all("zhajinhua.NTF_ROBOT_WEIGHT",{weight_list=get_robot_weight_list()})
        else
            send_to_gateway(uid,table_players[uid],'zhajinhua.NTF_PLAYER_OPERATE_STATUS',{uid = uid,buttons_status = buttons_status})
        end
        return true
    end

    return false
end

local function ntf_next_turn_info()
    if curr_zjh_instance then
        local next_player_id = curr_zjh_instance:get_next_player_uid()
        --curr_zjh_instance:reset_play_end_time()
        --local next_player_operate_time = curr_zjh_instance:get_play_end_time()
        --notify_all("zhajinhua.NTF_ROBOT_WEIGHT",{weight_list=get_robot_weight_list()})
        local run_cycle = curr_zjh_instance:get_run_round()
        notify_all('zhajinhua.NTF_NEXT_TURN_INFO',{next_player_uid = next_player_id, next_player_operate_time = zjh.PLAY_TIME, run_cycle = run_cycle})
    end
end

local function notify_event_status(uid)
    local state = get_player_state(uid)
    local online = get_player_online(uid)
    
    local msg = {uid = uid,state = state,online = online}
    notify_others('zhajinhua.NTF_EVENT',nil,msg)
end

local function notify_player_leave(uid,status)
    notify_others('zhajinhua.NTF_PLAYER_LEAVE',uid,{
        uid = uid,
        status = status
    })
end

local function watch_session(game_session,uid,observing)
    if game_session <= 0 then
        return
    end
    local gateway_id = game_session >> 31
    local request
    if observing then
        request = 'observe_fd'
    else
        request = 'unobserve_fd'
    end

    R().gateway(gateway_id):send('.watchdog','tablesvr',request,R().get_source(),game_session,uid)
end

local function get_rank_list()
    local rsp_rank_list = {} 

    for i=1,#record_list do
        local round_result = record_list[i]
        if round_result then
            for uid, score in pairs(round_result) do
                if not rsp_rank_list[uid] then
                    local one_player_info = {}
                    one_player_info.uid = uid
                    one_player_info.score = score
                    rsp_rank_list[uid] = one_player_info
                else
                    rsp_rank_list[uid].score = rsp_rank_list[uid].score + score
                end
            end
        end
    end

    table_sort(rsp_rank_list,function(a,b) return a.score > b.score end)

    for i=1,#rsp_rank_list do
        rsp_rank_list[i].rank = i
    end

    return rsp_rank_list
end

local function get_player_score(uid,rank_list)
    local curr_score = 0
    if not rank_list then
        rank_list = get_rank_list()
    end    
    for i=1,#rank_list do
        if uid == rank_list[i].uid then
            curr_score = rank_list[i].score
        end
    end
    return curr_score
end
 
--[[
    通知所有玩家有人坐下
]]
local function notify_player_sit(uid,is_seat,is_timeout,is_kick)
    if is_seat then
        local player_info = assert(player_info_list[uid])
        local player = make_player_info(uid)
        notify_all('zhajinhua.NTF_PLAYER_SEAT',{status = is_seat,player = player})
    else
         --获取下一个出手
        local player = {uid = uid}
        local r = is_kick and nil or STANDUP_KICK
        local ntf = {
            status = is_seat,
            player = player,
            is_timeout = is_timeout,
            reason = r,
        }
        notify_all('zhajinhua.NTF_PLAYER_SEAT',ntf)
    end
end

local function get_player_ip_list()
    local player_ip_list = {}
    for uid,player_data in pairs(player_info_list) do
        if player_data.login_ip then
            table_insert(player_ip_list,player_data.login_ip)
        end
    end
    return player_ip_list
end

local function notify_matchsvr_table_stats(is_delete)
    local table_stats = {}
    if is_delete then
        table_stats.table_gid = this_table_gid
        table_stats.table_type = self_table_type
        R().newmatchsvr(1):send('.table_mgr','delete_table_stats',table_stats)
    else
--        print("===================notify_matchsvr_table_stats=================")
        table_stats.table_type = self_table_type
        table_stats.left_num = zjh.MAX_PLAYER_NUM - get_player_num()
        table_stats.table_gid = this_table_gid
        table_stats.robot_num = get_robot_num()
        table_stats.human_num = get_human_num()
        table_stats.players_never_start = players_never_start
        table_stats.table_pattern = self_table_pattern
        table_stats.player_ip_list = get_player_ip_list()
       -- print(tostring_r(table_stats))
        R().newmatchsvr(1):send('.table_mgr','update_table_stats',table_stats)
    end
end

local function leave_round(uid)
    if curr_zjh_instance and not curr_zjh_instance:is_game_over() then
        local is_trun_next = curr_zjh_instance:leave(uid)
        if is_trun_next then
            curr_zjh_instance:turn_next_player()
            ntf_next_turn_info()
            send_next_player_operate_status()
            trigger_event('on_play',curr_zjh_instance:get_next_player_uid())
        end
    end
end

local function update_curr_round_need_player()
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata.open_robot then
        return
    end

    local robot_cnf = global_configs.robot[roomdata.robot_type or 0] or {}
    local round_player_rate = robot_cnf.num_rate or {[3] = 40,[4] = 50,[5] = 10}

    local rand_num = math_random(0,100)
    local tmp_value = 0
    for key,value in pairs(round_player_rate) do
        tmp_value = tmp_value + value
        if rand_num <= tmp_value then
            curr_round_need_player = key
            break
        end
    end
end

--[[
    设置玩家坐下
]]
local function sit_down(uid,pos)
    ordered_players[pos] = uid
    local player_info = assert(player_info_list[uid],'sit_down no player info' .. tostring(uid))
    player_info.position = pos
    player_status_list[uid] = PLAYER_STATUS_READY
    player_timeout[uid] = nil

    notify_player_sit(uid,true)
    notify_matchsvr_table_stats()
end

--[[
    设置玩家站起z
]]
local function stand_up(uid,is_timeout,is_kick)
    local player_info = player_info_list[uid] or {}
    if not player_info.position then
        leave_round(uid)
        return false
    end
    
    notify_player_sit(uid,false,is_timeout,is_kick)

    local pos = player_info.position

    leave_round(uid)

    player_info.position = nil
    ordered_players[pos] = nil
    --玩家站起清除掉玩家的状态
    player_status_list[uid] = nil

    notify_matchsvr_table_stats()
end



--玩这实时输赢op
function realTimeWinLose(uid, leave_time)
    if is_robot(uid) then return end
    local player_info = player_info_list[uid]
    if not player_info or not player_info.enter_time then 
        errlog("__________player_info.enter_time__是空的____", uid, player_info)
        return 
    end           
    local table_gid = player_info.enter_time .. "_" .. self_table_id .."_"..uid
    leave_time = leave_time or 0
    if player_info.all_win_lose == 0 and player_info.all_free == 0 then 
        --没产生流水就不记录了
        return
    end
    local data = {
        op = "user_leave_game",
        uid = uid,
        table_gid = table_gid, --唯一标记
        table_type = self_table_type,
        name = player_info.name,        
        enter_coins = player_info.enter_coins, --进入时身上金币
        enter_safe_coins = player_info.enter_safe_coins, --进入时保险箱金币 
        enter_time = player_info.enter_time, --进入时间
        leave_time = leave_time, --离开时间
        leave_coins = player_info.coins, --离开时身上金币
        leave_safe_coins = player_info.safe_box, --离开时保险箱金币
        win_lose = player_info.all_win_lose, --在玩游戏内产生的输赢（
        free = player_info.all_free, --玩游戏交上的台费
    }
    dbglog("_______user_leave_game_____",  data)
    billlog(data)
end

local function unlock_one_player(uid,table_gid)
    R().exdbsvr(1):send('.tlock_mgr','unset_on_table',uid,this_table_gid)
    curr_locked_uids[uid] = nil
    if not is_robot(uid) then
        R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type=0})
    end
end

local function on_leave(uid)
    local player_info = player_info_list[uid]
    if player_info then
        local is_robot = is_robot(uid)
        if not is_robot then
 
            if player_info.total_coins ~= 0 then                 
                -- local fee_score = 0
                -- local uid = player_info.uid
                -- local bet_coins = player_info.cur_bet
                -- local produce = player_info.total_coins + fee_score
                -- local win_lose = player_info.total_coins
                -- local free = fee_score
                -- if player_info.total_coins < 0 then 
                --     produce = 0
                -- end
                -- expand.sendSummary(self_table_type, uid, bet_coins, produce, win_lose, free)  
                -- player_info.cur_bet = 0   

                R().basesvr({key=uid}):send('.msg_handler','add_total_coins',uid,player_info.total_coins)                
                player_info.total_coins = 0
            end
        end
        local game_seesion = table_players[uid]
        stand_up(uid)
        realTimeWinLose(uid, os.time())

    
        --玩家有坐在位置上面了才通知其他玩家有人离开了
        -- if player_info.position then
        --     if ordered_players[player_info.position] then
        --         ordered_players[player_info.position] = nil
        --         --notify_player_leave(uid,reason)
        --         notify_matchsvr_table_stats()
        --     end
        -- end
        local init_coins = player_info.init_coins or 0
        player_status_list[uid] = nil
        player_info_list[uid] = nil
        reconnect_timout[uid] = nil
        table_players[uid] = nil

        if not is_robot then
            unlock_one_player(uid,this_table_gid)
            watch_session(game_seesion,uid,false)
            skynet.send(".table_mgr", "lua", "leave", uid)
        else
            --通知机器人退出
            robot_manager[uid]['on_exit'](robot_manager[uid])
            robot_manager[uid] = nil
        end

        --清掉牌局中的当前轮数的分数
        if curr_zjh_instance then
            curr_zjh_instance:clear_curr_round_score(uid)
        end
    end

end

local function leave(uid,reason)
    assert(table_players[uid])

    --如果是网络断开了
    if reason then
        local player_info = player_info_list[uid]
         if player_info then
            --如果不是观战 那么将角色标记为离线状态
            assert(table_players[uid] ~= OFFLINE_CLIENT_FD)
            table_players[uid] = OFFLINE_CLIENT_FD
            if player_info.position then
                notify_event_status(uid, reason)
            end
          --  print("leave by offline")
            reconnect_timout[uid] = util.get_now_time()
            return
        end
    end

    on_leave(uid)
end

local function check_auto_bet(curr_time)
    --不是机器人才有自动跟注
    local next_player_id = curr_zjh_instance:get_next_player_uid()
    local operate_delay_time = curr_zjh_instance:get_operate_delay_time()
    if not is_robot(next_player_id) then
        local player_info = player_info_list[next_player_id]
        if player_info then
            if curr_zjh_instance:is_auto_bet(next_player_id) then
                local buttons_status = curr_zjh_instance:get_buttons_status(next_player_id,player_info.coins,is_robot(next_player_id),player_info_list)
                --判断是否需要延时下注
                if buttons_status.can_continue_bet then
                    if operate_delay_time then
                        if curr_time >= operate_delay_time then
                            ntf_next_turn_info()
                            send_next_player_operate_status()
                            skynet.send(skynet.self(),'lua','REQ_ADD_SCORE',next_player_id,{add_type = 2},table_players[next_player_id])
                            --curr_zjh_instance:set_auto_bet(next_player_id,false)
                            curr_zjh_instance:clear_operate_delay_time()
                        end
                    else
                        if curr_time - (curr_zjh_instance:get_play_end_time() - zjh.PLAY_TIME) >= 1 then
                            skynet.send(skynet.self(),'lua','REQ_ADD_SCORE',next_player_id,{add_type = 2},table_players[next_player_id])
                        end
                    end
                else
                    --不能跟注清除状态
                    if operate_delay_time then
                        if curr_time >= operate_delay_time then
                            ntf_next_turn_info()
                            send_next_player_operate_status()
                            curr_zjh_instance:set_auto_bet(next_player_id,false)
                            curr_zjh_instance:clear_operate_delay_time()
                        end
                    else
                        curr_zjh_instance:set_auto_bet(next_player_id,false)
                    end
                end
            else
                --如果不是自动下注 那么检查是否需要延长操作时间
                if operate_delay_time then
                    if curr_time >= operate_delay_time then
                        ntf_next_turn_info()
                        send_next_player_operate_status()
                        curr_zjh_instance:clear_operate_delay_time()
                    end
                end
            end
        end
    else
        --机器人自动下注 如果有操作延时情况那么进行延时
        if operate_delay_time then
            if curr_time >= operate_delay_time then
                ntf_next_turn_info()
                send_next_player_operate_status()
                trigger_event('on_play',curr_zjh_instance:get_next_player_uid())
                curr_zjh_instance:clear_operate_delay_time()
            end
        end
    end
end

local function continue_compare(curr_time)
    --检查有没有需要继续比牌的玩家
    local next_player_id = curr_zjh_instance:get_next_player_uid()
    local player_info = player_info_list[next_player_id]
    if player_info then
        local buttons_status = curr_zjh_instance:get_buttons_status(next_player_id,player_info.coins,is_robot(next_player_id),player_info_list)
        local run_round = curr_zjh_instance:get_run_round()
        --需要强制比牌并且有操作延时那么才进行比牌
        if buttons_status.force_compare_uid then
            local roomdata = global_configs.roomdata[self_table_type]
            if roomdata and run_round >= roomdata.comparable_bet_round then --满轮首次比牌延迟0.5s
                curr_zjh_instance:set_max_round_frist_compare_delay_time(MAX_ROUND_COMPARE_DELAY_TIME)
            end

            local operate_delay_time = curr_zjh_instance:get_operate_delay_time()
            if operate_delay_time then
                if curr_time >= operate_delay_time then
                    skynet.send(skynet.self(),'lua','REQ_COMPARE_CARD',next_player_id,{dst_uid=buttons_status.force_compare_uid},table_players[next_player_id],true)
                    curr_zjh_instance:set_operate_delay_time()
                end
            else
                skynet.send(skynet.self(),'lua','REQ_COMPARE_CARD',next_player_id,{dst_uid=buttons_status.force_compare_uid},table_players[next_player_id],true)
                curr_zjh_instance:set_operate_delay_time()
            end
            return true
        end
    end

    return false
end

local function check_trusteed_player(curr_time)
    if curr_time >= curr_zjh_instance:get_play_end_time() then
        --第一次超时棋牌 第二次超时才站起
        local uid = curr_zjh_instance:get_next_player_uid()
        player_timeout[uid] = (player_timeout[uid] or 0) + 1
        dbglog("player_timeout[uid]===========",uid,player_timeout[uid])
        if player_timeout[uid] >= MAX_TIMEOUT_TIMES then
            stand_up(uid,true)
        else
            errlog("player_timeout[uid]===========",uid,player_timeout[uid])
            skynet.send(skynet.self(),'lua','REQ_GIVE_UP',uid,{},table_players[uid],true) --系统主动弃牌
        end
        --notify_matchsvr_table_stats()
        --如果该角色还是处于REGISTER_CLIENT_FD状态那么将玩家加入超时队列
        if table_players[uid] == REGISTER_CLIENT_FD then
            reconnect_timout[uid] = util:get_now_time()
        end
    else
        --需要继续比牌优先继续比牌 没有继续比牌再检查是否需要自动下注
        if not continue_compare(curr_time) then
            check_auto_bet(curr_time)
        end
    end
end

local function check_play(curr_time)
    if curr_zjh_instance:is_game_over() then
        return true
    end

    --轮到我出手了然而没有出手那么进行托管 托管逻辑就只是帮玩家站起
    check_trusteed_player(curr_time)

    return false
end

---------------------------------------------------------------------------
local function lock_one_player(uid,table_gid)
    local ok,succ = R().exdbsvr(1):call('.tlock_mgr','set_on_table',uid,table_gid,table_gid)
    if not ok then
        errlog(uid,'failed to set_on_table')
        return
    end

    if not succ then
        return
    end

    curr_locked_uids[uid] = true
    -- if not is_robot(uid) then
    --     R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type = self_game_type, curr_table_type = self_table_type})
    -- end
    return 0
end

local function get_all_human_uids()
    local uids = {}
    for uid,fd in pairs(table_players) do
        table_insert(uids,uid)
    end
    return uids
end

local function unlock_all_players()
    local uids = get_all_human_uids()
    for _,uid in pairs(uids) do
        unlock_one_player(uid,this_table_gid)
    end
end
---------------------------------------------------------------------------
local function get_player_enter_data(uid)
     --先拉取玩家信息
    local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
    if not ok then
        errlog(uid,'failed to get base_data',uid)
        return
    end
   
    --再拉取玩家的登入信息 跟大厅拉取
    local ok,enter_data = R().hallsvr({key=uid}):call('.msg_handler','get_enter_data',uid)
    if not ok then
        errlog(uid,'failed to get enter_data')
        enter_data = {}
    end
    
    local player_data = {
        uid = base_data.uid,
        name = enter_data.name or '',
        coins = base_data.coins,
        icon = enter_data.icon or '',
        sex = enter_data.sex or 1,
        affect_count = base_data.affect_count,
        affect_rate = base_data.affect_rate,
        vip_level = base_data.vip_level,
        icon_border = enter_data.icon_border,
        safe_box = base_data.safe_box,
    }

    return player_data    
end

local function get_table_conf()
    local conf = {}
    conf.curr_round = curr_round
    conf.creator_uid = creator_uid

    local roomdata = global_configs.roomdata[self_table_type]
    if roomdata then
        conf.dizhu = roomdata.dizhu
        conf.dingzhu = roomdata.dingzhu
        conf.max_bet_round = roomdata.max_bet_round
        conf.comparable_bet_round = roomdata.comparable_bet_round
        conf.max_look_round = roomdata.max_look_round
        conf.cost = roomdata.cost
        conf.table_name = roomdata.name
        conf.max_coins  = roomdata.max
        conf.table_type = self_table_type
    end

    local curr_time = util.get_now_time()
    if game_rest_time > curr_time then
        conf.end_time = game_rest_time - curr_time
    end

    return conf
end

local function get_player_info_list()
    local tmp_player_info_list = {}

    for _, uid in pairs(ordered_players) do
        local data = player_info_list[uid]
        if data then
            local player = make_player_info(uid)
            table_insert(tmp_player_info_list,player)
        end
    end
    return tmp_player_info_list
end

local function notify_player_enter(uid)
    local player_info = assert(player_info_list[uid])
    local player = make_player_info(uid)

    local play_effect = false
    local enter_word = ""
    local vip_level_conf = utils.getDataBykv(global_configs.vip,"level",player_info.vip_level or 0)
    if vip_level_conf and vip_level_conf.privilege[game_def.VIP_PRIVILEGE_TYPE_SIX] then
        play_effect = true
        enter_word = vip_level_conf.enter_word or ""
    end
    if curr_zjh_instance and curr_zjh_instance:check_player_in_round(uid) then
        play_effect = false
    end
    notify_all('zhajinhua.NTF_PLAYER_ENTER',{play_effect = play_effect,player = player,enter_word = enter_word})
end

local function enter(uid,client_fd,msg)
    if not table_players[uid] then
        errlog(uid,'zjhctable that player have not been registed yet')
        return false
    end

    -- if client_fd == ROBOT_CLIENT_FD then
    --     enter_robot_map[uid] = true
    -- end
    if not is_robot(uid) then
        R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type = self_game_type, curr_table_type = self_table_type})
    end
    if client_fd ~= ROBOT_CLIENT_FD then
        local data = get_player_enter_data(uid)
        if not data then
            errlog(uid,'zjhctable failed to get_player_enter_data')
            return false
        end

        local player_info = player_info_list[uid]
        --重新进来的玩家有可能此时处于站起状态了 因为该玩家有可能被托管站起了
        if not player_info then
            errlog(uid,'zjhctable failed to get player_info')
            return false
        end

        player_info.name = data.name
        player_info.icon = data.icon
        player_info.coins = data.coins
        player_info.sex = data.sex
        player_info.client_version = msg.client_version
        player_info.channel = msg.channel
        player_info.cur_channel = msg.cur_channel
        player_info.device_id = msg.device_id
        player_info.device_brand = msg.device_brand
        player_info.affect_count = data.affect_count
        player_info.affect_rate = data.affect_rate
        player_info.vip_level = data.vip_level
        player_info.icon_border = data.icon_border
        player_info.safe_box = data.safe_box
        player_info.enter_coins = data.coins
        player_info.enter_time = os.time()
        player_info.enter_safe_coins = data.safe_box
        player_info.all_win_lose = 0
        player_info.total_coins = 0
        player_info.all_free = 0
        player_info.os_system = data.os_system
        player_info.platform = data.platform      

        player_info.all_produce = 0
        player_info.all_bet = 0
        player_info.cur_bet = 0
    end
    
    table_players[uid] = client_fd
    reconnect_timout[uid] = nil

    local enter_info = {}
    enter_info.ftable_info = get_table_conf()
    enter_info.player_info_list = get_player_info_list()
    if curr_zjh_instance then
        local player_info = player_info_list[uid]
        if player_info then
           -- print("=======111",is_robot(uid))
            enter_info.game_status = curr_zjh_instance:get_game_status(uid,player_info.coins,is_robot(uid),player_info_list)
        end
    end

    --print_r(enter_info)

    return true,{game_type = self_game_type, table_type = self_table_type, zhajinhua_enter_info = enter_info}
end

local function set_ready(uid,ready)
    assert(player_status_list[uid])
    if ready then
        player_status_list[uid] = PLAYER_STATUS_READY
    else
        player_status_list[uid] = PLAYER_STATUS_NOREADY 
    end
    notify_event_status(uid)

    return true
end

local function are_all_players_ready()
    --这里的玩家数量一定是已经坐下的玩家数量了
    local player_num = get_player_num()
    if player_num < zjh.MIN_PLAYER_NUM then
        return false
    end
    
    local count = 0
    --检查座位上的玩家状态
 --   print(tostring_r(player_status_list))
    for _, uid in pairs(ordered_players) do
        local status = player_status_list[uid]
        if status == PLAYER_STATUS_READY then
            count = count + 1
        end
    end

    if count < zjh.MIN_PLAYER_NUM then
        return false
    end
    return true
end

local function is_ready_timeout(curr_time)
    if curr_time - ready_timeout  >= 5 then
        return true
    end
    return false
end

local function get_total_coins(robot_type)
    local ok,succ,total_coins = R().robotmgr(1):call('.msg_handler','get_total_coins',robot_type)
    if not ok then
        errlog("get_total_coins fail because ok is nil")
        return
    end

    return succ,total_coins
end

local function get_random_uid(second_uid)
    local uid_list = {}
    for _,uid in pairs(ordered_players) do
        if uid ~= second_uid then
            table_insert(uid_list,uid) 
        end
    end
    if #uid_list > 0 then
        local random_index = math_random(1,#uid_list)
        return uid_list[random_index]
    end
    return nil
end

local function get_random_player_uid()
    local player_ids = {}
    for _,uid in pairs(ordered_players) do
        if not is_robot(uid) then
           table_insert(player_ids,uid) 
        end
    end
    if #player_ids > 0 then
        local random_index = math_random(1,#player_ids)
        return player_ids[random_index]
    end
    return nil
end

local function get_random_robot_uid()
    local robot_ids = {}
    for _,uid in pairs(ordered_players) do
        if is_robot(uid) then
           table_insert(robot_ids,uid) 
        end
    end
    if #robot_ids > 0 then
        local random_index = math_random(1,#robot_ids)
        return robot_ids[random_index]
    end
    return nil
end

local function rand_deal_card_type()
    local deal_card_rate = global_configs.roomdata[self_table_type].deal_card_rate
    if not deal_card_rate then
        return
    end
    local total = deal_card_rate[1] + deal_card_rate[2] + deal_card_rate[3]
    local rand = math_random(1,total)
    local num = 0 
    for index,number in pairs(deal_card_rate) do
        num = num + number
        if rand <= num then
            return index
        end
    end
    return
end

local function check_have_robot(player_list)
    for _,uid in pairs(player_list) do
        if is_robot(uid) then
            return true
        end
    end

    return false
end

local function get_personal_system_store_result(robot_type) 
    local player_list = {}
    local player_no_robot_list = {}
    for _,uid in pairs(ordered_players) do
        if not is_robot(uid) then
            table_insert(player_no_robot_list,uid)
        end
        table_insert(player_list,uid)
    end

    local robot_store = global_configs.robot_store[self_table_type]
    local personal_control = global_configs.personal_control
    local is_have_robot = check_have_robot(player_list)
    is_curr_have_robot  = is_have_robot
    local gm_warn = (global_configs.gm_control or {}).warn_coins or 5000000
    local base_warn = robot_store.base_min or 0 

    return system_store.get_personal_system_store_result(self_table_type,player_no_robot_list,gm_warn,is_have_robot,base_warn)
end

local function get_best_cards_player()
    local special_uid
    local system_result,personal_uid,ctype
    local roomdata = global_configs.roomdata[self_table_type] 
    award_system_flag = false 
    control_player_uid = false
    if roomdata.open_robot and roomdata.robot_type then
        system_result,personal_uid,ctype = get_personal_system_store_result(roomdata.robot_type)
        system_result_type = system_result
        gm_control_uid = personal_uid
        local control_type = ctype
        print("zjh_get_personal_system_store_result==",system_result,personal_uid,control_type)
        if system_result then
            if system_result == constant.PERSONAL_STORE_WIN and personal_uid then   --控制玩家赢，给该玩家发最大牌型
                special_uid = personal_uid
                control_player_uid = personal_uid
            elseif system_result == constant.PERSONAL_STORE_LOSE and personal_uid then  --控制玩家输，给机器人发最大牌型
                special_uid = get_random_robot_uid(second_uid)
                control_player_uid = personal_uid
            elseif system_result == constant.SYSTEM_STORE_WIN then   --机器人拿最大牌
                --随机发牌策略
                special_uid = get_random_robot_uid()
            elseif system_result == constant.SYSTEM_STORE_LOSE then       --玩家拿最大牌
                special_uid = get_random_player_uid()
            elseif system_result == constant.AWARD_STORE_LOSE then
                special_uid = get_random_player_uid()
                if special_uid then
                    award_system_flag = true         
                end
            end
        end
    end
    dbglog("========111111get_best_cards_player",system_result,special_uid)
    return special_uid
end

local function check_player_sitdown(uid)
    for pos,_uid in pairs(ordered_players) do
        if uid == _uid then
            return true
        end
    end

    return false
end

local function get_player_affect_info(uid)
    local ok,base_data = R().basesvr{key=uid}:call('.msg_handler','get_base_data',uid)
    if not ok then
        errlog(uid,'failed to get base_data',uid)
        return 0,0
    end
    return base_data.affect_count,base_data.affect_rate
end

local function can_start()
    if curr_zjh_instance then
        return false,-1
    end

    local sitdown_num = get_player_num()
    if sitdown_num < zjh.MIN_PLAYER_NUM then
        return false,-2
    end

    --call回来再次检查玩家数量
    if get_player_num() < zjh.MIN_PLAYER_NUM then
        return false,-2
    end

    local zjh_instance = zjh:new()
    zjh_instance:init()
    zjh_instance:bind_type(self_table_type)

    --按位置索引顺序进入游戏
    local enter_game_player_list = {}
    for i=1, zjh.MAX_PLAYER_NUM, 1 do
        local uid = ordered_players[i]
        if uid then
            local player_info = player_info_list[uid]
            if player_info then
                zjh_instance:enter(uid,player_info.name)
                table_insert(enter_game_player_list,uid)
            end
        end
    end

    --设置所有玩家都处于游戏状态
    for _uid,status in pairs(player_status_list) do
        player_status_list[_uid] = PLAYER_STATUS_PLAYING
    end

    local ok = zjh_instance:check()
    if not ok then
        return false,-3
    end

    zjh_instance:shuffle()

    local special_uid = get_best_cards_player()
    local zjh_deal_card = global_configs.zjh_deal_card 
    zjh_instance:deal(special_uid,zjh_deal_card.change_rate)
    if special_uid and is_robot(special_uid) then
        robot_manager[special_uid]['system_win_robot'](robot_manager[special_uid])
    end
    --设置庄家状态
    zjh_instance:setingbanker_status(new_banker_uid)

    return zjh_instance
end

local function reduce_coins(uid,cost_coins,reason,...)
    --print("================cost_coins================",cost_coins)
    local ok,succ,ret = R().basesvr({key=uid}):call('.msg_handler','reduce_coins',uid,cost_coins,reason,...)
    if not ok then
        errlog(uid, "CZJH reduce_coins error because ok is nil")
        return
    end

    if not succ then
        errlog(uid, "CZJH reduce_coins error because succ is nil")
        return
    end

    R().basesvr{key=uid}:send('.msg_handler','add_lose_coins',uid,cost_coins)

    return {
        curr_coins = ret.curr
    }
end

--扣除底注
local function bet_begin_score()
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata then
        errlog(self_table_type, "CZJH bet_begin_score not find roomdata")
        return false
    end

    local player_list = curr_zjh_instance:get_player_list()
    local reduce_coins_list = {}
    for _, uid in pairs(player_list) do
        local robot = is_robot(uid)
        if robot then
            local player_info = player_info_list[uid]
            player_info.coins = player_info.coins - roomdata.dizhu
--            R().basesvr{key=uid}:send('.msg_handler','add_lose_coins',uid,roomdata.dizhu)
        else
            table_insert(reduce_coins_list,{f = reduce_coins,id = uid,
                params = {uid,roomdata.dizhu,reason.BET_COIN,{is_robot=robot}, get_extra_bill_info(uid)}})
            system_win_lose = system_win_lose + roomdata.dizhu
        end
    end

    --扣钱    
    local ok,results = cocall(5,reduce_coins_list)
    if not ok then
        errlog('ZJH:bet_begin_score failed to cocall',tostring_r(results))
        return false
    end

    --print(tostring_r(results))
    for uid,ret in pairs(results) do
        if ret and player_info_list[uid] then
            player_info_list[uid].coins = ret.curr_coins

            local player_info = player_info_list[uid]
            if player_info then
                -- player_info.all_win_lose = (player_info.all_win_lose or 0) - roomdata.dizhu
                player_info.total_coins = (player_info.total_coins or 0) - roomdata.dizhu      
                -- player_info.all_bet = (player_info.all_bet or 0) + roomdata.dizhu    
                -- player_info.cur_bet = (player_info.cur_bet or 0) + roomdata.dizhu 
            end
        end
    end

    return true
end

local function notify_start(cur_instance)
--    print(cur_instance:get_next_player_uid(),'now notify game is started....')

    if bet_begin_score() then
        curr_zjh_instance:bet_begin_score()
    end

    local ntf = {}
    for uid, player_info in pairs(player_info_list) do
        if not is_robot(uid) then
            ntf.game_status = cur_instance:get_game_status(uid,player_info.coins,is_robot(uid),player_info_list)
            ntf.fround = curr_round
            ntf.player_info = get_player_info_list()
            send_to_gateway(uid,table_players[uid],'zhajinhua.NTF_START',ntf)
        end
        --添加记录
        local bet_score = cur_instance:get_player_bet_score(uid)
        if bet_score > 0 then
            add_record(RECORD_TYPE_DIZHU,uid,nil,nil,bet_score)
        end
    end

    --通知庄家的按钮状态
    send_next_player_operate_status()
end

local function check_start(curr_time)
    local zjh_instance,msg = can_start()
    if not zjh_instance then
        dbglog('failed to can_start()',msg)
        return
    end

--    print('now start the game...')
    curr_zjh_instance = zjh_instance
    return true
end

local function get_result_info(game_result)
    local rand_info = {}
    local winners = game_result.winners
    local losers = game_result.losers
    for _, round_info in ipairs(winners) do
        rand_info[round_info.uid] = round_info.add_score
    end
    for _, round_info in ipairs(losers) do
        rand_info[round_info.uid] = round_info.add_score
    end
    return rand_info
end

local function add_coins(uid,coins,reason,...)
    local ok,succ,ret = R().basesvr{key=uid}:call('.msg_handler','add_coins',uid,coins,reason,...)
    if not ok then
        errlog(uid,'failed to add_coins ok is nil',coins)
        return
    end
    if not succ then
        errlog(uid,'failed to add_coins succ is nil',coins)
        return
    end

    R().basesvr{key=uid}:send('.msg_handler','sub_lose_coins',uid,coins)
    
    return {
        curr_coins = ret.curr,
    }
end

local function call_can_take_compensation(uid)
    local ok,given,ret = R().basesvr({key=uid}):call('.msg_handler','can_take_compensation',uid)
    if not ok then
        errlog(uid,'failed to call_take_compensation')
        return false
    end

    if not given then
        return false
    end

    return {
        left_times = ret,
        compensation_coins = global_configs.value.BASE_COMPENSATION_COINS
    }
end

local function can_take_compensation()
    local tasks = {}
    for _,uid in pairs(ordered_players) do
        if not is_robot(uid) then
            table_insert(tasks,{ f = call_can_take_compensation,id = uid,params = {uid} })
        end
    end
    
    local ok,results = cocall(5,tasks)
    if not ok then
        errlog('failed to cocall',tostring_r(results))
        return
    end

    for uid,r in pairs(results) do
        if r then
            local rsp = {
                left_compensation_times = r.left_times,
                compensation_coins = r.compensation_coins
            }

            send_to_gateway(uid,table_players[uid],'hall.NTF_COMPENSATION',rsp)

            -- billlog({ op = "bankrupt_register", uid = uid, game_type = self_game_type, 
            --     table_type = self_table_type, r = reason.BANKRUPT_REGISTER})
        end
    end
end

local function notify_take_compensation(uid)
    local ret = call_can_take_compensation(uid)
    --print(tostring_r(ret))
    if not ret then
        --errlog('failed to call call_can_take_compensation')
        return
    end

    local rsp = {
        left_compensation_times = ret.left_times,
        compensation_coins = ret.compensation_coins
    }
    send_to_gateway(uid,table_players[uid],'hall.NTF_COMPENSATION',rsp)
end

local function notify_compare_player_card()
    --通知玩家跟其比过牌的信息
    for _,uid in pairs(ordered_players) do
        local player_status = player_status_list[uid]
        if player_status and player_status == PLAYER_STATUS_PLAYING then
            --自己没弃牌才能看到其他人的牌型
            if not curr_zjh_instance:is_give_up(uid) then
                local player_card_list = curr_zjh_instance:get_compare_card_list(uid)
                send_to_gateway(uid,table_players[uid],'zhajinhua.NTF_COMPARE_PLAYER_CARD',{player_card_list = player_card_list})
            end
        end
    end
end

local function give_won_coins(uid,coins,reason)
    local robot = is_robot(uid)
    local ok,succ,ret = R().basesvr({key=uid}):call('.msg_handler',
        'give_won_coins',uid,coins,self_game_type,reason,{is_robot=robot},get_extra_bill_info(uid))
    if not ok then
        errlog(uid,'failed to give_won_coins',coins,succ)
        return
    end
    if not succ then
        errlog(uid,'failed to give_won_coins',coins)
        return
    end

    return {curr_coins = ret.curr,won_coins = ret.chged}
end

-- local function add_losing_times(uid)
--     --print(uid,"========================add_losing_times")
--     local ok,succ,ret = R().basesvr({key=uid}):call('.msg_handler',
--         'add_losing_times',uid,self_game_type)
--     if not ok then
--         errlog(uid,'failed to add_losing_times')
--         return
--     end
--     if not succ then
--         errlog(uid,'failed to add_losing_times')
--         return
--     end

--     return true
-- end

local function add_players_other_card_record_atts(winners,losers,player_realwin_map,fee_map)
    for _, player in pairs(winners) do        
        player.pay_fee   = fee_map[player.uid] or 0
        player.is_robot  = is_robot(player.uid)
        player.add_score = player_realwin_map[player.uid]
        player.is_banker = is_banker(player.uid)
    end

    for _, player in pairs(losers) do        
        player.pay_fee   = fee_map[player.uid] or 0
        player.is_robot  = is_robot(player.uid)
        player.is_banker = is_banker(player.uid)
    end
end

local function get_player_curr_coins(uid)
    if player_info_list[uid] then
        return player_info_list[uid].coins
    else
        --print("get_player_curr_coins---->",uid)
        local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
        if not ok then
            errlog(uid,'get_player_curr_coins-->failed to get base_data')
            return 0
        end

        return base_data.coins
    end

    return 0
end

local function check_today_coins_water_goal(uid,data)
    local seven_reward = global_configs.seven_reward
    local goal_list = {}
    for k,v in pairs(seven_reward) do  
        table_insert(goal_list,(v.coins_low + v.coins_hight)/2)
        table_insert(goal_list,coins_hight)
    end

    local function get_section_and_high(value)
        local section,section_high
        for num,data in pairs(seven_reward) do
            if value >= data.coins_low then
                section = num
                section_high = data.coins_hight
            end 
        end

        return section,section_high
    end
    
    for _,value in pairs(goal_list) do
        if (data.pre_coins_water or 0) < value and (data.curr_coins_water or 0) >= value then
            local section,section_high = get_section_and_high(data.curr_coins_water or 0)
            local ntf = {
                today_coins   = data.curr_coins_water or 0,
                section_count = section,
                section_hight = section_high or 0,
                section_total_count = #seven_reward,
            }
            send_to_gateway(uid,table_players[uid],'hall.NTF_SEVEN_REWARD_GOAL',ntf)
        end
    end
end

local function add_player_coins_water(winners,losers)
    local player_win = 0
    for _,record in pairs(winners) do
        if not is_robot(record.uid) then
            R().basesvr{key = record.uid}:send('.msg_handler','add_player_coins_water',record.uid,record.add_score)
            -- if ok and ret then
            --     check_today_coins_water_goal(uid,ret)
            -- end
        end
    end

    for _,record in pairs(losers) do
        if not is_robot(record.uid) then
            R().basesvr{key = record.uid}:send('.msg_handler','add_player_coins_water',record.uid,math.abs(record.add_score))
            -- if ok and ret then
            --     check_today_coins_water_goal(uid,ret)
            -- end
        end
    end
    return
end

local function notify_caishenjiadao(uid,coins)
--    print("=============notify_caishenjiadao",uid,coins)
    local curr_time = util.get_now_time()
    local countdown_time = global_configs.caishenjiadao.countdown_time or 10
    local end_time = curr_time + countdown_time + zjh.COMPARE_ANIMATION_TIME + 4
    caishen_coins_map[uid] = coins
    send_to_gateway(uid,table_players[uid],'table.NTF_CAISHENJIADAO',
    {end_time = end_time,trigger_coins = coins,game_type = self_game_type})
    billlog({op = "caishenjiadao",type = "trigger",uid = uid,table_type = self_table_type,coins = coins})
end

local function change_robot_store(system_win)
    local roomdata = global_configs.roomdata[self_table_type] or {}
    if not roomdata.robot_type then
        errlog("change_robot_store_conf_error")
        return
    end

    if system_win >= 0 then
        R().exdbsvr(1):send('.system_coins_mgr','add_system_coins',self_game_type,self_table_type,system_win)
    else
        if award_system_flag then --从奖励库存扣钱
            R().exdbsvr(1):send('.system_coins_mgr','reduce_award_coins',self_game_type,self_table_type,math.abs(system_win))
        else --从系统库存扣钱
            R().exdbsvr(1):send('.system_coins_mgr','sub_system_coins',self_game_type,self_table_type,math.abs(system_win))
        end
    end
end

local function get_player_win_coins(winners,losers,uid)
    if not winners or not losers or not uid then
        errlog("get_player_win_coins_error")
        return 0
    end

    for k,v in pairs(winners) do
        if v.uid == uid then
            return v.add_score
        end
    end

    for k,v in pairs(losers) do
        if v.uid == uid then
            return v.add_score
        end
    end

    return 0
end

local function write_card_record_log(winners, losers,player_realwin_map,fee_map)
    add_players_other_card_record_atts(winners,losers,player_realwin_map,fee_map)

    local player_win = 0
    local human_fee  = 0
    local add_score_map = {}
    local total_num = 0
    local change_store_coins = 0
    for _,player in pairs(winners) do
        if not player.is_robot then
            player_win = player_win + player.add_score
            human_fee = human_fee + (fee_map[player.uid] or 0)
            change_store_coins = change_store_coins + player.add_score + (fee_map[player.uid] or 0)
            if (control_player_uid or 0) > 0 and player.uid == (control_player_uid or 0) and system_result_type == constant.PERSONAL_STORE_WIN then
                local win_coins = player.add_score + (fee_map[player.uid] or 0)
                local ok,coins = R().basesvr({key=player.uid}):call('.msg_handler','update_player_control_value',player.uid,win_coins,self_table_type)
                print("update_player_control_value===111",ok,coins)
                gm_store_coins_add = (ok and coins) and coins or 0
            end
        end
        add_score_map[player.uid] = player.add_score
        total_num = total_num + 1
    end

    for _,player in pairs(losers) do
        if not player.is_robot then
            player_win = player_win + player.add_score
            change_store_coins = change_store_coins + player.add_score
            if (control_player_uid or 0) > 0 and player.uid == (control_player_uid or 0) and system_result_type == constant.PERSONAL_STORE_LOSE then
                local win_coins = player.add_score
                local ok,coins = R().basesvr({key=player.uid}):call('.msg_handler','update_player_control_value',player.uid,win_coins,self_table_type)
                print("update_player_control_value===111",ok,coins)
                gm_store_coins_add = (ok and coins) and -coins or 0
            end
        end
        add_score_map[player.uid] = player.add_score
        total_num = total_num + 1
    end

    change_store_coins = change_store_coins - gm_store_coins_add --把在GM库存里面扣的钱减掉
    change_robot_store(-change_store_coins) --增减系统库存

    local str_date = os.date("%Y%m%d%H%M%S")
    local side_list = {}
    local all_cards = curr_zjh_instance:get_all_player_tile_list()
    local player_list = curr_zjh_instance:get_player_list()
    for side,uid in pairs(player_list) do
        local side_info = {}
        side_info.uid = uid
        side_info.side = side
        side_info.cards = all_cards[uid] or {}
        side_info.card_type = curr_zjh_instance:get_card_type(uid)
        side_info.bet_coins = curr_zjh_instance:get_player_bet_score(uid)
        side_info.add_score = add_score_map[uid] or 0
        side_info.win = (add_score_map[uid] or 0) > 0

        table_insert(side_list,side_info)
    end

    local roomdata = global_configs.roomdata[self_table_type] or {}
    local total_score  = curr_zjh_instance:get_table_total_score()
    local run_round = curr_zjh_instance:get_run_round()
    local end_type = run_round < (roomdata.comparable_bet_round or 0) and 1 or 2
    local exinfo = {
        dizhu = roomdata.dizhu or 0,
        round = run_round,
        total_score = total_score,
        end_type = end_type,
        system_result = system_result_type or 0,
        control_uid = gm_control_uid or 0,
    }
    billlog({
            op = "card_record",
            table_gid = str_date .. "_" .. self_table_id, 
            game_type = self_game_type,table_type = self_table_type,
            begin_time = game_start_time,end_time = util.get_now_time(),
            curr_round = curr_round,password = self_password,
            winner_list = winners,loser_list = losers,system_win = -player_win,
            address = skynet.address(skynet.self()),
            side_list = side_list,
            exinfo = exinfo,
            total_num = total_num,
        })

    local total_coins = 0
    for uid,add_score in pairs(player_realwin_map) do
        if not is_robot(uid) then
            total_coins = total_coins + math_abs(add_score) + math_abs(fee_map[uid] or 0)
            R().basesvr({key=uid}):send('.msg_handler','add_today_win_coins',uid,add_score)
            R().basesvr({key=uid}):send('.msg_handler','add_play_count',uid,1)

             --检查是否触发财神驾到
            local player_info = player_info_list[uid]
            if player_info then
                local vip_level = player_info.vip_level
                print("===========ggggggggggggggg",uid,add_score,self_table_type,vip_level or 0)
                if system_store.check_trigger_caishenjiadao(uid,add_score,self_table_type,vip_level or 0) then
                    notify_caishenjiadao(uid,add_score)
                end
            end
            --添加玩家首冲进度
            -- R().activitysvr(1):send('.activity_mgr','act_add_first_charge_process',uid,add_score + (fee_map[uid] or 0))
        end
    end

    for _,record in pairs(losers) do
        -- local curr_coins = get_player_curr_coins(record.uid)
        if not is_robot(record.uid) then
            total_coins = total_coins + math_abs(record.add_score) + math_abs(fee_map[record.uid] or 0)
            R().basesvr({key=record.uid}):send('.msg_handler','add_play_count',record.uid,1)
        end

        -- if not is_robot(record.uid) and curr_coins <= constant.POCHAN_COINS then --记录破产日志
        --     billlog({op = "bankrupt_register",uid = record.uid,game_type = self_game_type,
        --         table_type = self_table_type,
        --         ret = curr_coins,
        --     })
        -- end
    end

    return total_coins
end

local function update_robot_store(total_coins)
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata or not roomdata.open_robot then
         return
    end
 
    local cnf = global_configs.robot_store[self_table_type]
    if not cnf then
         return
    end
 
   -- print("update_robot_storeaaaaaaaa",total_coins,award_system_flag)
    if award_system_flag then
         return
    end
 
    local fee_rate    = (cnf.fee_rate or 5) / 10000
    local award_rate  = (cnf.award_rate or 5) / 10000
    local fee_coins   = fee_rate * total_coins
    local award_coins = award_rate * total_coins
 
    print("total_coins============",total_coins,fee_coins,award_coins)
    R().exdbsvr(1):send('.system_coins_mgr','update_store',self_game_type,self_table_type,fee_coins,award_coins)
 end

local function check_store_transfer()
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata or not roomdata.open_robot then
        return
    end
 
    local cnf = global_configs.robot_store[self_table_type]
    if not cnf then
         return
    end

    local base_min  = cnf.base_min or 0
    local base_max  = cnf.base_max or 0
    local base_normal = cnf.base_normal or 0
    local data = {base_min = base_min,base_max = base_max,base_normal = base_normal,table_type = self_table_type}
    R().exdbsvr(1):send('.system_coins_mgr','check_store_transfer',self_game_type,data)
 end

local function get_control_coins(uid,winners,losers)
    local add_coins
    for _, player_record in pairs(winners) do
        if uid == player_record.uid then
            add_coins = player_record.add_score
            return add_coins
        end 
    end
    for _, player_record in pairs(losers) do
        if uid == player_record.uid then
            add_coins = player_record.add_score
            return add_coins
        end
    end

    return
end

-- local function update_control_store(add_coins,system_money_cost)
--     if add_coins > 0 then   
--         R().basesvr({key=control_player_uid}):send('.msg_handler','update_player_control_value',control_player_uid,add_coins,self_game_type)
--         if is_curr_have_robot and system_money_cost < 0 then
--             local gm_add_coins = math_abs(system_money_cost) < math_abs(add_coins) and math_abs(system_money_cost) or math_abs(add_coins)
--              --R().exdbsvr(1):send('.gm_coins_mgr','reduce_gm_coins',gm_add_coins,{uid=control_player_uid,table_type = self_table_type}) --减GM库存
--              gm_store_coins_add = -gm_add_coins
--         end
--     elseif add_coins < 0 then
--         R().basesvr({key=control_player_uid}):send('.msg_handler','update_player_control_value',control_player_uid,math_abs(add_coins),self_game_type)
--         if is_curr_have_robot and system_money_cost > 0 then
--             local gm_add_coins = math_abs(system_money_cost) < math_abs(add_coins) and math_abs(system_money_cost) or math_abs(add_coins)
--             --R().exdbsvr(1):send('.gm_coins_mgr','add_gm_coins',gm_add_coins,false,{uid=control_player_uid,table_type=self_table_type}) --加GM库存
--             gm_store_coins_add = gm_add_coins
--         end
--     end  
-- end

local function send_real_horse_message(winners_list)
    local roomdata = global_configs.roomdata[self_table_type] or {}
    local exinfo = cjson.encode({game_type = self_game_type})
    for _, player_record in pairs(winners_list) do
        local uid = player_record.uid
        if player_record.add_score > 0 then
            local player_info = player_info_list[uid]
            if player_info then
                R().mailsvr(1):send('.opration_message_worker','send_real_horse_message',constant.BROADCAST_IDS.BIDS_ZJH,
                {name = player_info.name,coin = player_record.add_score,vip_level = player_info.vip_level})
 
                R().mailsvr(1):send('.opration_message_worker','send_real_horse_message',constant.BROADCAST_IDS.GUIDE_BROAD,
                {vip_level = player_info.vip_level,name = player_info.name,game_name = roomdata.name or '',coin = player_record.add_score,exinfo = exinfo})
            end
        end
    end
end

--记录前三局输赢玩家的uid
local function robot_use_pic(winners,losers)
    local win_list = record_pic_player.win_list
    local lose_list = record_pic_player.lose_list
    if not win_list then
        win_list = {}
        record_pic_player.win_list = win_list
    end
    if not lose_list then
        lose_list = {}
        record_pic_player.lose_list = lose_list
    end
    if #win_list >= 3 then
        table_remove(win_list,1)
    end
    if #lose_list >= 3 then
        table_remove(lose_list,1)
    end
    win_list[#win_list+1] = {}
    lose_list[#lose_list+1] = {}

    local uid_win_list = win_list[#win_list]
    local uid_lose_list = lose_list[#lose_list]
    
    for _, player in pairs(winners) do
        if player.uid then
            if win_list[1] and win_list[2] then
                if win_list[1][player.uid] and win_list[2][player.uid] then
                    trigger_event('on_use_picture',player.uid,global_configs.robot_picture.zjh.win_three)
                end
            end
            uid_win_list[player.uid] = true
        end
    end
    for _, player in pairs(losers) do
        if player.uid then
            if lose_list[1] and lose_list[2] then
                if lose_list[1][player.uid] and lose_list[2][player.uid] then
                    trigger_event('on_use_picture',player.uid,global_configs.robot_picture.zjh.lose_three)
                end
            end
            uid_lose_list[player.uid] = true
        end
    end
end

local function audit_game_result(game_result)
    ---------------------------结算界面-------------------------------------
    --通知玩家跟其比过牌的信息
    notify_compare_player_card()

    gm_store_coins_add = 0 --结算开始先把gm库存增减值清0    assert(not record_list[curr_round])
    local rand_info = get_result_info(game_result)
    local winners = game_result.winners
    local losers = game_result.losers
    local bet_score = game_result.bet_score
    record_list[curr_round] = rand_info
    local winplayers = {}
    local loseplayers = {}
    local roomdata = global_configs.roomdata[self_table_type]
    local fee_percent = (roomdata.cost or 5 )/ 100

    local total_score = curr_zjh_instance:get_table_total_score()
    --获取当前金币

    local win_score = 0
    for _, player_record in pairs(winners) do
        new_banker_uid = player_record.uid
        win_score = player_record.add_score
        if is_robot(player_record.uid) then 
            local player_info = player_info_list[player_record.uid]
            player_info.coins = player_info.coins + total_score          
        else
            table_insert(winplayers,{ f = give_won_coins,id = player_record.uid,params = {player_record.uid,total_score,reason.WIN_COIN} })
            local player_info = player_info_list[player_record.uid]
            if player_info then
                -- player_info.all_win_lose = (player_info.all_win_lose or 0) +  win_score
                player_info.total_coins = (player_info.total_coins or 0) +  total_score   
                -- player_info.all_produce = (player_info.all_produce or 0) + total_score

                dbglog(player_record.add_score)             
            end
        end
    end

    for _, player_record in pairs(losers) do
        if not is_robot(player_record.uid) then
            R().basesvr({key=player_record.uid}):send('.msg_handler','add_losing_times',player_record.uid,self_game_type)
        end
    end

    --加钱    
    local ok,winresults = cocall(5,winplayers)
    if not ok then
        errlog('failed to cocall',tostring_r(results))
        return
    end

    -- if control_player_uid then    --个人控制库存加减钱
    --     local player_win = 0
    --     for _,player in pairs(winners) do
    --         if not is_robot(player.uid) then
    --             player_win = player_win + total_score
    --         end
    --     end
    --     for _,player in pairs(losers) do
    --         if not is_robot(player.uid) then
    --             player_win = player_win + player.add_score
    --         end
    --     end
    --     local system_money_cost = -player_win --系统输赢的钱

    --     local add_coins = get_control_coins(control_player_uid,winners,losers)
    --     if add_coins then
    --         --local warn_coins = (global_configs.gm_control or {}).warn_coins or 50000000
    --         --local match_gm_store = system_store.is_match_gm_store(add_coins,warn_coins)
    --         --print("match_gm_store========",is_curr_have_robot,match_gm_store,warn_coins)
    --         if add_coins > 0 and system_result_type == constant.PERSONAL_STORE_WIN or (add_coins < 0 and system_result_type == constant.PERSONAL_STORE_LOSE) then
    --             dbglog("=================1111111control add_coins",add_coins)
    --             update_control_store(add_coins,system_money_cost)
    --         end
    --     end
    -- end

    --添加玩家金币流水
    add_player_coins_water(winners,losers)
    local str_date = os.date("%Y%m%d%H%M%S")
    --扣台费
    local cost_player = {}
    local fee_map = {}
    local player_realwin_map = {}
    for _, player_record in pairs(winners) do
        local uid = player_record.uid
        local fee_score = math_floor(player_record.add_score * fee_percent) 
        player_realwin_map[uid] = player_record.add_score - fee_score
        player_record.add_score = player_realwin_map[uid]
        fee_map[uid] = fee_score

        if is_robot(uid) then
            local player_info = player_info_list[uid]
            player_info.coins = player_info.coins - fee_score
--            R().basesvr{key=uid}:send('.msg_handler','add_lose_coins',uid,fee_score)
        else
            table_insert(cost_player,{ f = reduce_coins,id = uid,
                params = {uid,fee_score,reason.PAY_FEE,{is_robot = is_robot(uid)}, get_extra_bill_info(uid)} })
            -- system_win_lose = system_win_lose + fee_score
            local player_info = player_info_list[uid]
            if player_info then
                --玩家赢增加输赢
                player_info.all_win_lose = (player_info.all_win_lose or 0) + player_record.add_score
                player_info.total_coins = (player_info.total_coins or 0) - fee_score               
                player_info.all_free = player_info.all_free + fee_score

                local bet_coins = curr_zjh_instance:get_player_bet_score(player_record.uid)
                player_info.all_bet = (player_info.all_bet or 0) + bet_coins
                dbglog("total_coins:",player_info.total_coins,fee_score)
                player_info.cur_bet = 0
            end

            local bet_coins = curr_zjh_instance:get_player_bet_score(player_record.uid)
            system_win_lose = (system_win_lose - bet_coins) - (win_score - fee_score)               
            local win_lose = player_record.add_score --去掉了台费
            local produce = win_lose + fee_score + bet_coins

            errlog("_2222_player_record_win___",player_record.uid, bet_coins)
            expand.sendSummary(self_table_type, player_record.uid, bet_coins, produce, win_lose, fee_score)  
                   


        end
    end

    local ok,results = cocall(5,cost_player)
    if not ok then
        errlog('pay_fee failed to cocall',tostring_r(results))
        return false
    end

    for uid,ret in pairs(results) do
        if ret then
            local player_info = player_info_list[uid]
            if player_info then
                --player_info.coins = ret.curr
                player_info.coins = ret.curr_coins
            end
        end
    end

    for _, player_record in ipairs(winners) do
        local isrobot = is_robot(player_record.uid)

        player_record.left_score = get_player_curr_coins(player_record.uid)
        local player_info = player_info_list[player_record.uid]
        if player_info then
            if isrobot then
                player_info.valid_times =  player_info.valid_times + 1
            else
                R().basesvr({key=player_record.uid}):send('.msg_handler','add_total_coins',player_record.uid,player_info.total_coins)
                       
                player_info.total_coins = 0       
            end
        end
        --添加牌局记录
        add_record(RECORD_TYPE_RESULT,player_record.uid,nil,nil,player_record.add_score)
    end
    for _, player_record in ipairs(losers) do
        local isrobot = is_robot(player_record.uid)
        player_record.left_score = get_player_curr_coins(player_record.uid)
        local player_info = player_info_list[player_record.uid]
        if player_info then
            if isrobot then
                player_info.valid_times =  player_info.valid_times + 1
            else
                R().basesvr({key=player_record.uid}):send('.msg_handler','add_total_coins',player_record.uid,player_info.total_coins)
                player_info.total_coins = 0              
                player_info.cur_bet = 0
                local bet_coins = curr_zjh_instance:get_player_bet_score(player_record.uid)
                player_info.all_win_lose = (player_info.all_win_lose or 0) - math_abs(player_record.add_score)
                player_info.all_bet = (player_info.all_bet or 0) + bet_coins
            end         
        end
        
        if not isrobot then
            local bet_coins = curr_zjh_instance:get_player_bet_score(player_record.uid)
            local win_lose = player_record.add_score --去掉了台费
            --local produce = win_lose - bet_coins
            print("_2222_player_record_lose___", player_record.uid, bet_coins, win_lose)
            expand.sendSummary(self_table_type, player_record.uid, bet_coins, 0, win_lose, 0)  
        end
                 
    end


    notify_all('zhajinhua.NTF_GAMEOVER', {winners = winners,losers = losers})
    send_real_horse_message(winners)
    robot_use_pic(winners,losers)

    local total_coins = write_card_record_log(winners,losers,player_realwin_map,fee_map)
    if not award_system_flag then
        total_coins = total_coins - math_abs(gm_store_coins_add)
        update_robot_store(total_coins)
    end
    check_store_transfer() --转移库存

    for uid,value in pairs(bet_score) do
        if not is_robot(uid) then
            R().basesvr({key=uid}):send('.msg_handler','add_person_water',uid,value,is_robot(uid))
            billlog({ op   = "water_history",  
                table_gid  = str_date .. "_" .. self_table_id,
                table_type = self_table_type,
                uid        = uid,
                value      = value,
                is_robot   = is_robot(uid),
                r          = constant.WATER_TYPE.WATER_BET
            })

        end
    end
    sendLoseWinToFriendServer(system_win_lose)
    system_win_lose = 0
    return true
end

local function check_reconnect_timeout(curr_time)
    --检查离线超时玩家是否需要做踢掉操作
    for uid, offline_time in pairs(reconnect_timout) do
        if curr_time - offline_time >= 120 then
            leave(uid)
            --leave_round(uid)
            --notify_matchsvr_table_stats()
        end
    end
end

local function have_player()
    for uid,_ in pairs(player_info_list) do
        if not is_robot(uid) then
            return true
        end
    end
    return false
end

-- local function again_kick_robot(robot_ids_list)
--     for position,uid in pairs(ordered_players) do
--         if is_robot(uid) then
--             local player_info = player_info_list[uid]
--             if player_info and player_info.valid_times >= player_info.max_times then
--                 table_insert(robot_ids_list,uid)
--                 leave(uid)
--             end
--         end
--     end
-- end

local function dissmiss_table()
    local uids = {}
    local robots = {}
    for uid,player_info in pairs(player_info_list) do
        local game_session = table_players[uid]
        local robot = is_robot(uid)
        leave(uid)
        if not robot then
            send_to_gateway(uid,game_session,'zhajinhua.RSP_LEAVE',{result=error_code.RSP_SUCESS})
            watch_session(game_session,uid,false)
        end
        
        skynet.send('.table_mgr','lua','leave',uid)

        local roomdata = global_configs.roomdata[self_table_type]
        if robot and roomdata and roomdata.robot_type then
            table_insert(robots,{type=roomdata.robot_type, uid=uid, coins=player_info.coins})
        end
            
        table_insert(uids,uid)
    end

    notify_matchsvr_table_stats(true)  --更新桌子
    skynet.send('.table_mgr','lua','on_table_delete',self_table_id,uids)    --删除状态
    --R().robotmgr(1):send('.msg_handler','put_back_robots',robots) --归还机器人
    return true
end

local function check_stop_table()
    if stopping_server then        
        billlog({op = "stop_table",status = curr_status,password = self_password})
        closing_server = true --直接关闭桌子
        return true
    end

    return false
end

local function check_close_table(curr_time)
    if not game_register_time then
        game_register_time = curr_time
    end

    local closable = false
    if closing_server then
        closable = true
    else 
        --如果已经没有玩家了 并且桌子已经处于游戏结束状态那么就关闭游戏 游戏没有开局 那么就关闭游戏了
        if not have_player() and not curr_zjh_instance and curr_round ~= 0 then
            closable = true
        end

        if not have_player() and curr_round == 0 and curr_time - game_register_time >= 10 then
            closable = true
        end
    end

    if not closable then
        return
    end
    if is_on_match() and not closing_server then
        print("table is on match",closable)
        return
    end

    local ok,ret = xpcall(dissmiss_table,debug.traceback)
    if not ok then
        errlog(ret)
    end

    billlog({op = "close_table",status = curr_status,password = self_password})
    dbglog('now delete this table',self_table_id,uids)
    skynet.exit()
end

local function reset_all_player_ready()
    for _, uid in pairs(ordered_players) do
        player_status_list[uid] = PLAYER_STATUS_READY
    end
end

local function check_all_enter(curr_time)
    if curr_time >= waiting_enter_timeout then
        return true
    end

    for uid,fd in pairs(table_players) do
        if fd == REGISTER_CLIENT_FD then
            return false
        end
    end

    return true
end

local function finish_game()
    local ok,result = curr_zjh_instance:get_game_result()
    if not ok then
        return
    end

    trigger_event('on_game_over')
    --notify_all("zhajinhua.NTF_ROBOT_WEIGHT",{weight_list=get_robot_weight_list()})
    
    return result
end

local function run_robots(new_robot_list)
    for _,AIobj in pairs(new_robot_list) do
        skynet.fork(function() 
            AIobj:update() 
        end)
    end
end

local function get_robot_type()
    local robot_type = 2      --1.类型1;2.类型2
    local sum = 0
    local robot_type_rate = global_configs.zjh_robotAI.no_look.robot_type_rate or {50,50}
    for _, v in pairs(robot_type_rate) do
        sum = sum + v
    end

    local rand_num = math_random(1,sum)
    if rand_num <= robot_type_rate[1] then
        robot_type = 1
    end

    return robot_type
end

load_robot = function(curr_time)
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata then
        errlog('load_robot fail because roomdata is nil')
        return
    end

    --判断是否开放机器人
    if not roomdata.open_robot then
        return
    end

    local robot_type = roomdata.robot_type or 0
    local robot_cnf  = global_configs.robot[robot_type]
    if not robot_cnf then
        errlog('load_robot fail because robot is nil')
        return 
    end

    local add_robot_num = curr_round_need_player - get_player_num()
    if add_robot_num <= 0 then
        return
    end
    --如果没有玩家那么不去加载机器人
    if not have_player() then
        return
    end
    
    if curr_time <= last_load_robot_time then
        return
    end
    last_load_robot_time = curr_time + math_random(3,5)

    --如果座位上的机器人大于两个人那么也不去加载机器人了
    --if get_robot_num() >= 2 then
    --    return
    --end

    --随机拉取1到两个机器人
    --local robot_num = math_random(1,2)
    local robot_type = roomdata.robot_type
    local conis_limit = {robot_cnf.min_coin,robot_cnf.max_coin}
    local left_num = table_def.game_player_num[self_game_type] - get_player_num()
    add_robot_num = math_min(left_num,add_robot_num)
    if add_robot_num <= 0 then
        return
    end

    local ok,succ,ret_map = R().robotmgr(1):call('.msg_handler','get_robots',add_robot_num,robot_type,conis_limit)
    if not ok then
        errlog("add robot is fail because ok is nil")
        return
    end

    if not succ then
        errlog("add robot is fail because succ is nil")
        return
    end

    if not ret_map then
        errlog("add robot is fail because ret_map is nil")
        return
    end

    --add_robot_num = 0
    --再次检查人数是否已经满了 如果满了将机器人送回
    if get_player_num() + #ret_map > table_def.game_player_num[self_game_type] then
        errlog("add robot beyond seat",get_player_num(),#ret_map)
        R().robotmgr(1):send('.msg_handler','put_back_robots',ret_map)
        return
    end

    --[[if are_all_players_ready() then
        R().robotmgr(1):send('.msg_handler','put_back_robots',ret_map)
        return
    end]]

    local curr_time = util.get_now_time()
    local new_robot_list = {}
    for _, robot_info in pairs(ret_map) do
        local position = 1
        while ordered_players[position] do
            position = position + 1
        end

        local robot_uid = robot_info.uid
        local player_data = {
            uid = robot_uid,
            match_type = self_table_type,
            begin_time = curr_time,
            name = robot_info.name,
            coins = robot_info.coins,
            sex = robot_info.sex,
            icon = robot_info.icon,
            last_chat_time = 0,
            last_ping_time = curr_time,
            max_times = math_random(5,15), --机器人有效期牌局次数
            valid_times = 0,
            icon_border = robot_info.icon_border,
            type = get_robot_type()         --机器人类型（类型1，类型2）
        }

        table_players[robot_uid] = ROBOT_CLIENT_FD
        ordered_players[position] = robot_uid
        player_data.position = position
        player_info_list[robot_uid] = player_data
        player_status_list[robot_uid] = PLAYER_STATUS_READY   --默认进来就是准备了

        local robot_obj = game_robot.new(robot_uid,player_data,robot_type,robot_AI,skynet.self(),ROBOT_CLIENT_FD,table_pattern)
        robot_manager[robot_uid] = robot_obj
--        print(robot_uid,"add robot obj")
        --触发进入事件
        trigger_event('on_register',robot_uid)
        table_insert(new_robot_list,robot_obj)
    end

    --通知匹配服更新人数
    notify_matchsvr_table_stats()

    --fork robot协程
    run_robots(new_robot_list)
end

-- local function kick_player()
--     local roomdata = global_configs.roomdata[self_table_type]
--     if not roomdata then
--         errlog('kick_player fail because roomdata is nil')
--         return
--     end

--     local robot_ids_list = {}
--     for _,uid in pairs(ordered_players) do
--         local is_kick = false
--         local player_info = player_info_list[uid]
--         if player_info then
--             if player_info.coins < roomdata.min or player_info.coins < roomdata.cost then
--                 is_kick = true
--             else
--                 if roomdata.max ~= 0 and player_info.coins > roomdata.max then
--                     is_kick = true
--                 end
--             end
--             if is_kick and not is_robot(uid) then
--                 stand_up(uid)
--             end
--         end
--     end
-- end

local function get_lose_coins(uid)
    local ok,ret = R().basesvr{key=uid}:call('.msg_handler','get_lose_coins',uid)
    if not ok then
        errlog(uid,'failed to get_lose_coins ok is nil',ok)
        return
    end

    return ret
end

local function kick_player_and_robot()
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata then
        errlog('pay_fee fail because roomdata is nil')
        return
    end

    --这里在检查一把是否要将玩家和机器人进行站起或者离开
    local robot_ids_list = {}
    for _,uid in pairs(ordered_players) do
        local is_kick = false
        local player_info = player_info_list[uid]
        if player_info then
            if player_info.coins < roomdata.min or player_info.coins < roomdata.cost then
                print("is_kick====11111",player_info.coins,roomdata.min,roomdata.cost)
                is_kick = true
            else
                if roomdata.max ~= 0 and player_info.coins > roomdata.max then
                    print("is_kick====2222",player_info.coins,roomdata.max)
                    is_kick = true
                end
            end

            if is_robot(uid) and player_info.valid_times >= player_info.max_times then
                print("is_kick====3333",player_info.valid_times,player_info.max_times)
                is_kick = true
            end

            if is_kick then
                if is_robot(uid) then
                    leave(uid)
                else
                    stand_up(uid,false,true)
                end
            end
        end
    end
end

--返回金币
local function return_coins(results)
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata then
        errlog('pay_fee fail because roomdata is nil')
        return
    end

    local payers = {}
    for uid,ret in pairs(results) do
        if ret then
            local robot = is_robot(uid)
            table_insert(payers,{ f = add_coins,id = uid,params = {uid,roomdata.cost,reason.COST_COIN_ERROR_BACK,{is_robot=robot},get_extra_bill_info(uid)} })  
        end
    end
    
    local ok,ask = cocall(5,payers)
    if not ok then
        errlog('assert failed to cocall',tostring_r(ask))
    end

    --检查下是否每个人都扣款成功
    for uid,ret in pairs(ask) do
        if ret and ret.curr_coins then
            local player_info = player_info_list[uid]
            if player_info then
                player_info.coins = ret.curr_coins
                local fd = assert(table_players[uid])
                utils.notify_money_changed(uid,{coins = ret.curr_coins},fd)
            end
        else
            errlog(uid,'failed to return_roomcards')
        end
    end
end

--扣除台费
local function pay_fee()
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata then
        errlog(self_table_type,'pay_fee fail because roomdata is nil')
        return false
    end

    --再检查一次是否需要踢走没钱的玩家
    kick_player_and_robot()

    --小于一个人就不能开始了
    local sitdown_num = get_player_num()
    if sitdown_num < zjh.MIN_PLAYER_NUM then
        return false
    end

    --开始扣钱
    local total_robot_fee = 0
    local cost_player = {}
    for _, uid in pairs(ordered_players) do
        local robot = is_robot(uid)
        if robot then
            total_robot_fee = total_robot_fee + roomdata.cost
        end
        table_insert(cost_player,{ f = reduce_coins,id = uid,
            params = {uid,roomdata.cost,reason.PAY_FEE,{is_robot=robot}, get_extra_bill_info(uid)} })
    end
    local ok,results = cocall(5,cost_player)
    if not ok then
        errlog('pay_fee failed to cocall',tostring_r(results))
        return false
    end

    --覆盖金币
    local is_return = false
    for uid,ret in pairs(results) do
        if not ret then
            errlog(uid,'pay_fee failed to cocall...')
            is_return = true
            break
        end
    end

    --call回来再检查人数够不够开始 不够就不开始了
    local sitdown_num = get_player_num()
    if sitdown_num < zjh.MIN_PLAYER_NUM then
        is_return = true
    end

    --如果有一个人扣除不成功那么回退金币
    if is_return then
        return_coins(results)
        return false
    end

    --进行通知金币变化
    if not is_return then
        local chged_list = {}
        for uid,ret in pairs(results) do
            local player_info = player_info_list[uid]
            if player_info then
                player_info.coins = ret.curr_coins
                table_insert(chged_list,{uid=uid,coins=ret.curr_coins})
            else 
                errlog(uid,"player_info nil")
            end
        end
        notify_all("table.NTF_MONEY_CHANGED",{chged_list=chged_list})
    end

    return true
end

local function notify_count_down()
    notify_all('zhajinhua.NTF_COUNTDOWN',{end_time = zjh.GAME_REST_TIME})
end

local function notify_cancel_count_down()
    notify_all('zhajinhua.NTF_CANCEL_COUNTDOWN',{})
end

local function update_players_never_start()
    for uid in pairs(table_players) do
        if not is_robot(uid) then
            dbglog("update_players_never_start:", self_table_id, uid)
            players_never_start[uid] = nil
        end
    end
end

local function check_robot_leave_game_over()
    --人满机器人离开一人 机器人钱不够离开 
    --上面没人离开时 机器人按概率离开
    local already_exit
    if #ordered_players >= (table_def.game_player_num[self_game_type] or 5) then
        local leave_uid = get_random_robot_uid()
        if leave_uid then
            print("on_leave_now==111",#ordered_players,table_def.game_player_num[self_game_type] or 5)
            leave(leave_uid)
            --trigger_event("on_leave_now",leave_uid)
            already_exit = true
        end
    end

    local roomdata = global_configs.roomdata[self_table_type]
    local robot_type = roomdata.robot_type or -1
    for _,uid in pairs(ordered_players) do
        local player_info = player_info_list[uid]
        if is_robot(uid) and player_info and player_info.coins < roomdata.min then
            print("on_leave_now==222",player_info.coins,roomdata.min)
            leave(uid)
           --trigger_event("on_leave_now",uid)
           already_exit = true
        end
    end

    local robot = global_configs.robot[robot_type]
    if not already_exit and robot then
        local rate = robot.exit_rate or 0
        for _,uid in pairs(ordered_players) do
            local player_info = player_info_list[uid]
            if is_robot(uid) and player_info and math_random(0,100) < rate then
                print("on_leave_now==333",rate)
                leave(uid)
               --trigger_event("on_leave_now",uid)
               break
            end
        end
    end
end


-------------------------------游戏主循环------------------------
function update(curr_time)
    --print('=============curr status',tostring(curr_status),self_table_id)
    if curr_status == TABLE_STATUS_REGISTERED then
        update_curr_round_need_player()
        load_robot(curr_time)
        curr_status = TABLE_STATUS_WAITING_ENTER
        waiting_enter_timeout = curr_time + 3
    elseif curr_status == TABLE_STATUS_WAITING_ENTER then
        if check_all_enter(curr_time) then
            curr_status = TABLE_STATUS_WAITTING_READY
            ready_timeout = curr_time
        end
    elseif curr_status == TABLE_STATUS_WAITTING_READY then
        if are_all_players_ready() then
            curr_status = TABLE_STATUS_WAITTING_REST
            game_rest_time = curr_time+zjh.GAME_REST_TIME
            notify_count_down()
        end
    elseif curr_status == TABLE_STATUS_WAITTING_REST then
        if curr_time > game_rest_time then
            curr_status = TABLE_STATUS_CHECK_START
        else
            if not are_all_players_ready() then
                curr_status = TABLE_STATUS_WAITTING_READY
            end
        end
    elseif curr_status == TABLE_STATUS_CHECK_START then
        if check_start(curr_time) then
            --通知游戏开始的数据
            curr_round = curr_round + 1
            --开始前删除记录
            check_del_record()
            trigger_event('on_start',curr_zjh_instance)
            notify_start(curr_zjh_instance)
            game_start_time = curr_time
            curr_status = TABLE_STATUS_PLAYING
            trigger_event('on_start_play')
        else --如果检查没法开始那么又回到等待状态
            curr_status = TABLE_STATUS_RESTART
            ready_timeout = curr_time
            notify_cancel_count_down()
        end
    elseif curr_status == TABLE_STATUS_PLAYING then
        if check_play(curr_time) then
            curr_status = TABLE_STATUS_GAMEOVER
            game_over_time = curr_time
        end
    elseif curr_status == TABLE_STATUS_GAMEOVER then
        local is_finish = true
        --如果是因为比牌结束游戏那么需要预留4S给客户端播放比牌动画
        if curr_zjh_instance:get_operate_delay_time() and curr_time - game_over_time < zjh.COMPARE_ANIMATION_TIME then
            is_finish = false
        end

        if is_finish then
            curr_zjh_instance:clear_operate_delay_time()
            local game_result = finish_game()
            if game_result then
                local ok,ret = xpcall(audit_game_result,debug.traceback,game_result)
                if not ok then
                    errlog(ret)
                end
            end
            --设置旧的庄家ID
            --old_banker_uid = curr_zjh_instance:get_banker_uid()
            curr_status = TABLE_STATUS_ANIMATION
            game_animation_time = curr_time

            update_players_never_start()
        end
    elseif curr_status == TABLE_STATUS_ANIMATION then
        if curr_time - game_animation_time > zjh.COINS_ANIMATION_TIME then
            --通知补助
            --can_take_compensation()
            kick_player_and_robot()
            check_stop_table() --停服
            check_robot_leave_game_over()
            curr_status = TABLE_STATUS_RESTART
        end
    elseif curr_status == TABLE_STATUS_RESTART then
        curr_zjh_instance = nil
        curr_status = TABLE_STATUS_REGISTERED
        reset_all_player_ready() --默认将场上所有玩家自动设置为准备
        load_config()
    else
        errlog('unknown status...',curr_status)
    end

    check_reconnect_timeout(curr_time)
    check_close_table(curr_time)
end

local function game_update()
    curr_status = TABLE_STATUS_REGISTERED
    while true do
        local curr_time = util.get_now_time()
        local ok,ret = xpcall(update,debug.traceback,curr_time)
        if not ok then
            errlog(ret)
        end
        skynet.sleep(50)
    end
end

function internal.get_player_num()
    return get_player_num()
end

function internal.sync_table_stats()
    local table_stats = {}
    table_stats.table_gid = this_table_gid
    table_stats.left_num = zjh.MAX_PLAYER_NUM - get_player_num()
    table_stats.robot_num = get_robot_num()
    table_stats.human_num = get_human_num()
    table_stats.players_never_start = players_never_start
    table_stats.table_pattern = self_table_pattern
    dbglog("sync_table_stats:", self_table_type, tostring_r(table_stats))
    return self_table_type,table_stats
end

local function newmatch_register_all(player_data_list)
    local result = {}
    local failed_list = {}
    local success_list = {}

    set_on_match()
    for _,player_data in pairs(player_data_list) do
        local uid = player_data.uid

        if lock_one_player(uid,this_table_gid) then
            if get_player_num() >= zjh.MAX_PLAYER_NUM then
                unlock_one_player(uid,this_table_gid)
                table_insert(failed_list,player_data)
            else
                local position = 1
                while ordered_players[position] do
                    position = position + 1
                end

                if not table_players[uid] then
                    table_players[uid] = REGISTER_CLIENT_FD
                    ordered_players[position] = uid
                    player_data.position = position
                    player_data.last_chat_time = 0
                    player_data.last_ping_time = curr_time
                    player_data.init_coins = player_data.coins
                    player_data.all_win_lose = 0
                    player_data.all_free = 0
                    player_data.all_produce = 0
                    player_data.all_bet = 0         
                    player_data.cur_bet = 0            

                    player_info_list[uid] = player_data
                    player_status_list[uid] = PLAYER_STATUS_READY   --默认进来就是准备了
                    table_insert(success_list,player_data.uid)
                    notify_player_enter(uid)

                    dbglog("new_player:", self_table_id, uid)
                    players_never_start[uid] = true
                end
            end
        else
            errlog("newmatch_register_all lock player fail",uid)
        end
    end
    unset_on_match()

    result.failed_list = failed_list
    result.success_list = success_list
    local table_stats = {}
    table_stats.table_type = self_table_type
    table_stats.left_num = zjh.MAX_PLAYER_NUM - get_player_num()
    table_stats.table_gid = this_table_gid
    table_stats.game_type = self_game_type
    table_stats.robot_num = get_robot_num()
    table_stats.human_num = get_human_num()
    table_stats.players_never_start = players_never_start
    table_stats.table_pattern = self_table_pattern
    table_stats.player_ip_list = get_player_ip_list()
    result.table_stats = table_stats
    if not game_update_co then
        game_update_co = skynet.fork(game_update)
    end

    return result
end

function internal.newmatch_register_all(player_data_list)
    return newmatch_register_all(player_data_list)
end

---------------------------客户端请求类处理----------------------------------------
--[[
    请求看牌操作
]]
function handler.REQ_LOOK_CARD(uid,msg,game_session)
    if curr_status ~= TABLE_STATUS_PLAYING then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.GAME_NOT_START})
        dbglog("REQ_LOOK_CARD curr_status is not playing !! ",curr_status)
        return false
    end

    if not curr_zjh_instance then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.GAME_NOT_START})
        dbglog("REQ_LOOK_CARD curr_zjh_instance is nil !! ")
        return false
    end

    if curr_zjh_instance:is_game_over() then
        dbglog("REQ_LOOK_CARD game is over !! ")
        return false
    end

    --桌子里面没有该玩家了
    local player_info = player_info_list[uid]
    if not player_info then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.NO_PLAYER_IN_TABLE})
        dbglog("REQ_LOOK_CARD error player_info is nil", uid)
        return false
    end

    --玩家还没坐下无法点击查看
    if not player_info.position then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_LOOK_CARD error player_info.position is nil", uid)
        return false
    end

    --玩家位置出错了
    if uid ~= ordered_players[player_info.position] then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_LOOK_CARD uid ~= ordered_players[player_info.position]", uid)
        return false
    end

    --检查一下状态
    local player_status = player_status_list[uid]
    if not player_status or player_status ~= PLAYER_STATUS_PLAYING then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.NOT_IN_PLAYERING})
        dbglog("REQ_LOOK_CARD error player_status is nil or player_status ~= PLAYER_STATUS_PLAYING", uid)
        return false
    end

    if not curr_zjh_instance:can_look(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.LOOK_CARD_FAIL})
        dbglog("REQ_LOOK_CARD error ok is false", ok)
        return false
    end

    --send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.RSP_SUCESS})
    -- local zjh_deal_card = global_configs.zjh_deal_card
    -- local look_change_condition = zjh_deal_card.look_change_condition
    local card_type, tile_list = curr_zjh_instance:look_card(uid)
    send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.RSP_SUCESS, card_type = card_type, tile_list = tile_list})
    notify_others('zhajinhua.NTF_LOOK_CARD',uid,{uid = uid,tile_list = {}})  --tile_list客户端测试时开放

    --机器人看牌后有几率触发表情
    trigger_event('on_use_picture',uid,global_configs.robot_picture.zjh.look_card)

    --刷新一下新的按钮
    send_self_operate_status(uid)
    player_timeout[uid] = nil --清空连续超时记录

    -- trigger_event('on_look_card_weight',uid)
    --notify_all("zhajinhua.NTF_ROBOT_WEIGHT",{weight_list=get_robot_weight_list()})  --客户端测试时开放
    --机器人
    trigger_event('on_look_card',uid)
    add_record(RECORD_TYPE_LOOK,uid)

    --通知牌型事件
    if not is_robot(uid) then
        events.on_card_type({uid = uid,game_type = self_game_type,table_type = self_table_type,card_type = card_type}) 
        --R().exdbsvr(1):send('.event_mgr','trigger','on_card_type',{uid = uid,game_type = self_game_type,table_type = self_table_type,card_type = card_type})
    end

    return true
end

--[[
    请求放弃牌
]]
function handler.REQ_GIVE_UP(uid,msg,game_session,auto)
    if curr_status ~= TABLE_STATUS_PLAYING then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.GAME_NOT_START})
        dbglog("REQ_GIVE_UP curr_status is not playing !! ",curr_status)
        return false
    end

    if not curr_zjh_instance then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.GAME_NOT_START})
        dbglog("REQ_GIVE_UP curr_zjh_instance is nil !! ")
        return false
    end

    if curr_zjh_instance:is_game_over() then
        dbglog("REQ_GIVE_UP game is over !! ")
        return false
    end

    --桌子里面没有该玩家了
    local player_info = player_info_list[uid]
    if not player_info then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.NO_PLAYER_IN_TABLE})
        dbglog("REQ_GIVE_UP error player_info is nil", uid)
        return false
    end

    if not player_info.position then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_GIVE_UP error player_info.position is nil", uid)
        return false
    end

    --玩家位置出错了
    if uid ~= ordered_players[player_info.position] then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_GIVE_UP uid ~= ordered_players[player_info.position]", uid)
        return false
    end

    --检查一下状态
    local player_status = player_status_list[uid]
    if not player_status or player_status ~= PLAYER_STATUS_PLAYING then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.NOT_IN_PLAYERING})
        dbglog("REQ_GIVE_UP error player_status is nil or player_status ~= PLAYER_STATUS_PLAYING", uid)
        return false
    end

    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_GIVE_UP error player is have operate lock", uid)
        return false
    end

    --在延迟比牌期间不能弃牌
    if curr_zjh_instance:get_operate_delay_time() then
        dbglog("REQ_GIVE_UP error because player in operate delay time")
        return false
    end

    if not curr_zjh_instance:can_give_up(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.GIVE_UP_FAIL})
        dbglog("REQ_GIVE_UP curr_zjh_instance:give_up failed", uid)
        return false
    end

    send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.RSP_SUCESS})

    notify_all('zhajinhua.NTF_GIVE_UP',{uid = uid})
    if not auto then
        player_timeout[uid] = nil ----清空连续超时记录
    end
    --添加记录
    add_record(RECORD_TYPE_GIVEUP,uid)
    trigger_event('on_use_picture',uid,global_configs.robot_picture.zjh.give_up)
    --放弃牌局
    local is_trun_next = curr_zjh_instance:give_up(uid)

    if is_trun_next then
        curr_zjh_instance:turn_next_player()
        ntf_next_turn_info()
        send_next_player_operate_status()
        --机器人
        trigger_event('on_play',curr_zjh_instance:get_next_player_uid())
    end

    return true
end

local function check_roll_back(uid)
    if curr_status ~= TABLE_STATUS_PLAYING then
        errlog(uid,'check_roll_back because curr_status ~= TABLE_STATUS_PLAYING')
        return true
    end

    if curr_zjh_instance:is_game_over() then
        errlog(uid,'check_roll_back because curr_zjh_instance:is_game_over()')
        return true
    end

    if not curr_zjh_instance:is_my_turn(uid) then
        errlog(uid,'check_roll_back because is not my trun')
        return true
    end
    
    return false
end

--[[
    请求下注
]]
function handler.REQ_ADD_SCORE(uid,msg,game_session)
    if curr_status ~= TABLE_STATUS_PLAYING then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.GAME_NOT_START})
        dbglog("REQ_ADD_SCORE curr_status is not playing !! ",curr_status)
        return false
    end

    if not curr_zjh_instance then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.GAME_NOT_START})
        dbglog("REQ_ADD_SCORE curr_zjh_instance is nil !! ")
        return false
    end

    if curr_zjh_instance:is_game_over() then
        dbglog("REQ_ADD_SCORE game is over !! ")
        return false
    end

    --桌子里面没有该玩家了
    local player_info = player_info_list[uid]
    if not player_info then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.NO_PLAYER_IN_TABLE})
        dbglog("REQ_ADD_SCORE error player_info is nil", uid)
        return false
    end

    if not player_info.position then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_ADD_SCORE error player_info.position is nil", uid)
        return false
    end

    --玩家位置出错了
    if uid ~= ordered_players[player_info.position] then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_ADD_SCORE uid ~= ordered_players[player_info.position]", uid)
        return false
    end

    --检查一下状态
    local player_status = player_status_list[uid]
    if not player_status or player_status ~= PLAYER_STATUS_PLAYING then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.NOT_IN_PLAYERING})
        dbglog("REQ_ADD_SCORE error player_status is nil or player_status ~= PLAYER_STATUS_PLAYING", uid)
        return false
    end

    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_ADD_SCORE error player is have operate lock", uid)
        return false
    end

    local bet_score = msg.bet_score
    -- if bet_score == 0 then
    --     bet_score = nil
    -- end

    local ok,cost_score = curr_zjh_instance:can_add_score(uid,bet_score)
    if not ok then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.BET_FAIL})
        errlog("REQ_ADD_SCORE curr_zjh_instance:add_score(uid,multiple) error", uid)
        return false
    end

    if not is_robot(uid) then
        local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
        if not ok then
            send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.BET_FAIL})
            errlog(uid,'REQ_ADD_SCORE add_score failed to get base_data',uid)
            return false
        end

        --非比牌情况下如果身上的钱不够跟注了那么无法进行跟注
        
        if base_data.coins < cost_score then
            send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.GOLD_IS_NOT_ENOUGH})
            errlog(uid, 'REQ_ADD_SCORE fail because base_data.coins < cost_score')
            return false
        end
    end


    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_ADD_SCORE error player is have operate lock", uid)
        return false
    end

    --这里开始锁住玩家的操作了
    curr_zjh_instance:set_operate_lock(uid,true)

     --扣钱
    local robot = is_robot(uid)
    local ret
    if robot then
        player_info.coins = player_info.coins - cost_score
        --R().basesvr{key=uid}:send('.msg_handler','add_lose_coins',uid,cost_score)
    else
        ret = reduce_coins(uid,cost_score,reason.BET_COIN,{is_robot=robot},get_extra_bill_info(uid))
        if not ret then
            curr_zjh_instance:set_operate_lock(uid,false)
            send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.BET_FAIL})
            errlog(uid,'REQ_ADD_SCORE reduce_coins failed to',uid)
            return false
        end
        --检查是否要回滚金币
        if check_roll_back(uid) then
            add_coins(uid,cost_score,reason.BET_COIN_BACK,{is_robot=robot},get_extra_bill_info(uid))
            curr_zjh_instance:set_operate_lock(uid,false)
            send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.BET_FAIL})
            errlog(uid,'roll back player coin',uid)
            return false
        end

        system_win_lose = system_win_lose + cost_score
        local player_info = player_info_list[uid]
        if player_info then
            -- player_info.all_win_lose = (player_info.all_win_lose or 0) - cost_score
            player_info.total_coins =(player_info.total_coins or 0) - cost_score            
            -- player_info.all_bet = (player_info.all_bet or 0) + cost_score
            -- player_info.cur_bet = (player_info.cur_bet or 0) + cost_score
            dbglog("total_coins:",player_info.total_coins,cost_score)
        else 
            errlog(uid,"player_info nil")
        end
    end

    --如果此时无法
    local is_bet = true
    
    curr_zjh_instance:add_score(uid,cost_score,is_bet,msg.add_type)

    --覆盖一下玩家缓存中的金币 展示使用
    if player_info and not robot then
        player_info.coins = ret.curr_coins
    end

    send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.RSP_SUCESS})

    local rsp = {
        uid = uid,
        bet_score = cost_score,
        left_score = player_info.coins,
        total_score = curr_zjh_instance:get_table_total_score(),
        add_type = msg.add_type,
        cur_bet_score = curr_zjh_instance:get_player_bet_score(uid)
    }

    notify_all('zhajinhua.NTF_ADD_SCORE',rsp)

    utils.notify_money_changed(uid,{coins = player_info.coins},game_session)
    
    --添加牌局记录
    local record_type = RECORD_TYPE_ADD
    if msg.add_type == ADD_TYPE_GEN then
        record_type = RECORD_TYPE_FOLLOW
    end
    add_record(record_type,uid,nil,nil,cost_score)


    trigger_event('on_add_socre_weight',uid,msg.add_type)
    if msg.add_type == ADD_TYPE_JIA then
        trigger_event('on_use_picture',uid,global_configs.robot_picture.zjh.add_score)
    elseif msg.add_type == ADD_TYPE_GEN then
        trigger_event('on_use_picture',uid,global_configs.robot_picture.zjh.bet_score)
        --检查一下有没有机器人加注过，有的话该机器人触发表情包
        local record_last_score = curr_zjh_instance:get_ming_score_record()
        local robot_uid = record_last_score[1] or record_last_score[3]
        if robot_uid then
            trigger_event('on_use_picture',uid,global_configs.robot_picture.zjh.player_bet)
        end
    end
    --notify_all("zhajinhua.NTF_ROBOT_WEIGHT",{weight_list=get_robot_weight_list()})

    --如果当前是我出手才切换下一个出手
    curr_zjh_instance:turn_next_player()
    ntf_next_turn_info()

    --通知下一个玩家的按钮状态
    send_next_player_operate_status()
    player_timeout[uid] = nil --清空连续超时记录

    curr_zjh_instance:set_operate_lock(uid,false)

    --机器人
    trigger_event('on_play',curr_zjh_instance:get_next_player_uid())

    return true
end

--[[
    请求比牌
]]
function handler.REQ_COMPARE_CARD(uid,msg,game_session,is_force_compare)
    if curr_status ~= TABLE_STATUS_PLAYING then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.GAME_NOT_START})
        dbglog("REQ_COMPARE_CARD curr_status is not playing !! ",curr_status)
        return false
    end

    if not curr_zjh_instance then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.GAME_NOT_START})
        dbglog("REQ_COMPARE_CARD curr_zjh_instance is nil !! ")
        return false
    end

    if curr_zjh_instance:is_game_over() then
        dbglog("REQ_COMPARE_CARD game is over !! ")
        return false
    end

    --桌子里面没有该玩家了
    local player_info = player_info_list[uid]
    if not player_info then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.NO_PLAYER_IN_TABLE})
        dbglog("REQ_COMPARE_CARD error player_info is nil", uid)
        return false
    end

    if not player_info.position then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_COMPARE_CARD error player_info.position is nil", uid)
        return false
    end

    --玩家位置出错了
    if uid ~= ordered_players[player_info.position] then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_COMPARE_CARD uid ~= ordered_players[player_info.position]", uid)
        return false
    end

    --检查一下状态
    local player_status = player_status_list[uid]
    if not player_status or player_status ~= PLAYER_STATUS_PLAYING then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.NOT_IN_PLAYERING})
        dbglog("REQ_COMPARE_CARD error player_status is nil or player_status ~= PLAYER_STATUS_PLAYING", uid)
        return false
    end

    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_ADD_SCORE error player is have operate lock", uid)
        return false
    end

    --检查是否可以下注
    local ok,cost_score = curr_zjh_instance:can_add_score(uid)
    if not ok then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.COMPARE_FAIL})
        errlog("REQ_COMPARE_CARD curr_zjh_instance:add_score(uid,multiple) error", uid)
        return false
    end

    local left_coins = 0
    if not is_robot(uid) then
        local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
        if not ok then
            send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.COMPARE_FAIL})
            errlog(uid,'REQ_COMPARE_CARD add_score failed to get base_data',uid)
            return false
        end
        left_coins = base_data.coins
    else
        -- local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
        left_coins = player_info.coins
        -- errlog("============robot=========",base_data.coins,left_coins)
    end

    local enough_money = true
    local is_force = false
    local dst_uid = msg.dst_uid
    if left_coins < cost_score then
        enough_money = false
        cost_score = left_coins
        --钱不够强制跟下一家比
        dst_uid = curr_zjh_instance:get_next_compare_player_uid()
        is_force = true
    end

    --检查一下是否可以比牌
    if not curr_zjh_instance:can_compare(uid,dst_uid,is_force) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.COMPARE_FAIL})
        errlog("REQ_COMPARE_CARD not curr_zjh_instance:can_compare", uid, dst_uid)
        return false
    end

    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_ADD_SCORE error player is have operate lock", uid)
        return false
    end

    --这里开始锁住玩家的操作了
    curr_zjh_instance:set_operate_lock(uid,true)

    if cost_score > 0 then
        --扣钱
        local robot = is_robot(uid)
        if robot then
            player_info.coins = player_info.coins - cost_score
            -- R().basesvr{key=uid}:send('.msg_handler','add_lose_coins',uid,cost_score)
        else
            local ret = reduce_coins(uid,cost_score,reason.BET_COIN,{is_robot=robot},get_extra_bill_info(uid))
            if not ret then
                curr_zjh_instance:set_operate_lock(uid,false)
                return false
            end

            --检查是否要回滚金币
            if check_roll_back(uid) then
                add_coins(uid,cost_score,reason.BET_COIN_BACK,{is_robot=robot},get_extra_bill_info(uid))
                curr_zjh_instance:set_operate_lock(uid,false)
                return false
            end
            system_win_lose = system_win_lose + cost_score
            --覆盖一下玩家缓存中的金币 展示使用
            if player_info then
                player_info.coins = ret.curr_coins
                -- player_info.all_win_lose = (player_info.all_win_lose or 0) - cost_score
                player_info.total_coins = player_info.total_coins - cost_score
                -- player_info.all_bet = (player_info.all_bet or 0) + cost_score
                -- player_info.cur_bet = (player_info.cur_bet or 0) + cost_score

                dbglog("total_coins:",player_info.total_coins,cost_score)

            end
        end
        curr_zjh_instance:add_score(uid,cost_score,enough_money,2)
    end

    --开始比牌逻辑
    local win,is_trun_next,src_type,dst_type = curr_zjh_instance:compare(uid,dst_uid)
    local win_uid = 0
    local fail_uid = 0
    if win then
        win_uid = uid
        fail_uid = dst_uid
    else
        win_uid = dst_uid
        fail_uid = uid
    end

    send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.RSP_SUCESS})

    local rsp = {
        src_uid = uid,
        dst_uid = dst_uid,
        win_uid = win_uid,
        fail_uid = fail_uid,
        bet_score = cost_score,
        left_score = player_info.coins,
        total_score = curr_zjh_instance:get_table_total_score(),
        cur_bet_score = curr_zjh_instance:get_player_bet_score(uid),
        src_type = src_type,
        dst_type = dst_type,
    }
    notify_all('zhajinhua.NTF_COMPARE_CARD', rsp)
    --添加比牌记录
    add_record(RECORD_TYPE_COMPARE,uid,dst_uid,win_uid)

    utils.notify_money_changed(uid,{coins = player_info.coins},game_session)

    curr_zjh_instance:set_operate_delay_time()

    trigger_event('on_compare_card_weight',uid)
    if win then
        --机器人比牌胜利,被比牌失败时有几率触发表情
        trigger_event('on_use_picture',uid,global_configs.robot_picture.zjh.compare_succ)
        trigger_event('on_use_picture',dst_uid,global_configs.robot_picture.zjh.compare_des_failed)
    else
        --机器人比牌失败，被比牌胜利时有几率触发表情
        trigger_event('on_use_picture',uid,global_configs.robot_picture.zjh.compare_failed)
        trigger_event('on_use_picture',dst_uid,global_configs.robot_picture.zjh.compare_des_succ)
    end
    --notify_all("zhajinhua.NTF_ROBOT_WEIGHT",{weight_list=get_robot_weight_list()})
    if is_trun_next then
        --如果处于强制比牌阶段 那么只有比输了才需要切换下家出手 比赢了继续出手
        if is_force_compare then
            if not win then
                curr_zjh_instance:turn_next_player()
            else
                curr_zjh_instance:reset_play_end_time()
            end
        else
            --如果处于手动比牌 那么只有玩家的钱足够才切换下家出手 如果玩家的钱不够那么不切换下家出手
            if enough_money then
                curr_zjh_instance:turn_next_player()
            else
                if not win then
                    curr_zjh_instance:turn_next_player()
                else
                    curr_zjh_instance:reset_play_end_time()
                end
            end
        end
    end

    curr_zjh_instance:set_operate_lock(uid,false)

    return true
end

--[[
    请求聊天
]]
function handler.REQ_CHAT(uid,msg)
    print("=======================ggggggggggggggg",uid,tostring_r(msg))
    local player_info = assert(player_info_list[uid])
    if not player_info then
        errlog(uid,"REQ_CHAT failed you are not a player_info")
        return false
    end

    if not player_info.position then
        errlog(uid,"REQ_CHAT not have position")
        return false
    end

    local curr_time = util.get_now_time()

    if player_info.last_chat_time and curr_time - player_info.last_chat_time < 1 then
        send_to_gateway(uid,table_players[uid],'table.RSP_CHAT',{result = error_code.REQ_CHAT_TOO_FAST})
        return false
    end

    player_info.last_chat_time = curr_time

    send_to_gateway(uid,table_players[uid],'table.RSP_CHAT',{result = error_code.RSP_SUCESS})

    local ntf = {
        uid = uid,
        type = msg.type,
        picture_id = msg.picture_id,
        content = msg.content,
        voice = msg.voice,
        content_id = msg.content_id
    }

    notify_all('table.NTF_CHAT',ntf)

    return true
end

--用户请求坐下
function handler.REQ_PLAYER_SEAT(uid,msg)
    local position = msg.position
    local status = msg.status
    --判断坐下位置是否有效
    if position < 1 or position > zjh.MAX_PLAYER_NUM then
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.ERROR_HAVE_STAND_UP})
        return false
    end

    if status then
        --判断玩家是否有该玩家
        local player_info = player_info_list[uid]
        if not player_info then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.NO_PLAYER_IN_TABLE})
            return false
        end

        --判断该玩家是否已经坐下了
        if player_info.position then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.SEAT_FAIL_HAVE_SEAT})
            return false
        end

        --判断该位置是否已经被占用了
        if ordered_players[position] then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.SEAT_IS_EMPLOY})
            return false
        end

        local roomdata = global_configs.roomdata[self_table_type]
        if not roomdata then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.SEAT_FAIL})
            errlog('REQ_PLAYER_SEAT fail because roomdata is nil')
            return false
        end

        --这里在检查一把是否要将玩家和机器人进行站起或者离开
        if player_info.coins < roomdata.min then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.GOLD_IS_NOT_ENOUGH})
            return false
        end

        if roomdata.max ~= 0 and player_info.coins > roomdata.max then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.TO_MUCH_COIN})
            return false
        end

        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.RSP_SUCESS})
        --坐下
        sit_down(uid,position)
    else
        local player_info = player_info_list[uid]
        if not player_info then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.NO_PLAYER_IN_TABLE})
            return false
        end

        if not player_info.position then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.UP_FAIL_NOT_HAVE_SEAT})
            return false
        end

        if uid ~= ordered_players[player_info.position] then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.UP_FAIL_NOT_HAVE_SEAT})
            return false
        end

        --判断玩家之前有没有其他还未解锁的操作
        if curr_zjh_instance then
            --锁住操作了就不让玩家站起
            if curr_zjh_instance:get_operate_lock(uid) then
                send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.ERROR_IN_OPERATE_LOCK})
                errlog("stand_up error player is have operate lock", uid)
                return false
            end

            --在延迟比牌期间不能站起
            if curr_zjh_instance:get_operate_delay_time() then
                dbglog("REQ_PLAYER_SEAT error because player in operate delay time")
                return false
            end
        end

        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.RSP_SUCESS})
        --站起
        stand_up(uid)
    end

    --notify_matchsvr_table_stats()

    return true
end

--换桌
function handler.REQ_TABLE_CHANGE(uid,msg,game_session)
    local roomdata = global_configs.roomdata
    if not roomdata[self_table_type] then
        errlog(self_table_type,"check_can_change_table but roomdata is nil")
        return false
    end

    local player_info = player_info_list[uid]
    if not player_info then
        dbglog("REQ_TABLE_CHANGE error player_info is nil", uid)
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_TABLE_CHANGE',{result = error_code.PERMISSION_DENIDE})
        return false
    end

    local can_change = true
    --如果开局了那么 那么无论什么人都可以直接换桌
    if curr_zjh_instance then
        if not curr_zjh_instance:is_game_over() then
            --如果已经开局了 那么只有还在正常游戏中的人才不可以换桌 放弃失败离开的人可以直接换桌
            if player_info.position then
                local player_status = player_status_list[uid]
                if player_status and player_status == PLAYER_STATUS_PLAYING then
                    if curr_zjh_instance:player_isvalid(uid) then
                        can_change = false
                    end
                end
            end
        end
    end

    --可以换桌了 先通知玩家离开
    if can_change then
        local change_table_type
        local table_data = global_configs.roomdata[self_table_type]
        --优先满足在当前场次换桌
        if player_info.coins >= table_data.min then
            if table_data.max == 0 then --无限大
                change_table_type = self_table_type
            end
            if table_data.max ~= 0 and player_info.coins <= table_data.max then
                change_table_type = self_table_type
            end
        end

        for table_type,table_data in pairs(roomdata) do
            if change_table_type then
                break
            end
            local game_type = game_def.get_game_type(table_type)
            if game_type == self_game_type and player_info.coins >= table_data.min then
                if table_data.max == 0 or (table_data.max ~= 0 and player_info.coins <= table_data.max) then
                    change_table_type = table_type
                end
            end
        end
        if not change_table_type then
            send_to_gateway(uid,game_session,'table.RSP_TABLE_CHANGE',{result = error_code.GOLD_IS_NOT_ENOUGH})
            return  
        end

        --离开游戏
        leave(uid)
        send_to_gateway(uid,game_session,'table.RSP_TABLE_CHANGE',{result = error_code.RSP_SUCESS})

        --请求匹配服进行匹配了
        local roomdata = global_configs.roomdata[change_table_type]
        local user_data = {
            uid = uid,
            table_type = change_table_type,
            begin_time = util.get_now_time(),

            name = player_info.name,
            coins = player_info.coins,
            sex = player_info.sex,
            icon = player_info.icon,
            old_table_gid = this_table_gid,
            login_ip = player_info.login_ip,
            ip_limit = roomdata.ip_limit or false,
        }   

        local ok = R().newmatchsvr(1):call('.table_mgr','match_player',user_data)
        if not ok then
            errlog(uid,'REQ_TABLE_CHANGE failed to match player')
        end
    else
        send_to_gateway(uid,game_session,'table.RSP_TABLE_CHANGE',{result = error_code.IN_GAME_CAN_NOT_CHANGE})
    end

    return true
end

--换游戏
function handler.REQ_GAME_CHANGE(uid,msg,game_session)
    local roomdata_list = global_configs.roomdata or {}
    local roomdata = roomdata_list[msg.table_type]
    if not roomdata then
        errlog(self_table_type,"check_game_change_table but roomdata is nil")
        return false
    end

    local player_info = player_info_list[uid]
    if not player_info then
        dbglog("REQ_GAME_CHANGE error player_info is nil", uid)
        send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.PERMISSION_DENIDE})
        return false
    end

    --游戏中不可以换游戏
    if curr_zjh_instance and (not curr_zjh_instance:is_game_over()) then --游戏中
        if player_info.position and curr_zjh_instance:player_isvalid(uid) then
            local player_status = player_status_list[uid]
            if player_status and player_status == PLAYER_STATUS_PLAYING then
                send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.IN_GAME_CAN_NOT_CHANGE})
                return false
            end
        end
    end

    if player_info.coins < (roomdata.min or 0) then
        send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.GOLD_IS_NOT_ENOUGH})
        return false
    end

    if (roomdata.max or 0) ~= 0 and player_info.coin > (roomdata.max or 0) then
        send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.GOLD_OUT_OF_MAX})
        return false
    end

    --离开游戏
    leave(uid)
    send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.RSP_SUCESS})

    --请求匹配服进行匹配了
    local user_data = {
        uid = uid,
        table_type = msg.table_type,
        begin_time = util.get_now_time(),

        name = player_info.name,
        coins = player_info.coins,
        sex = player_info.sex,
        icon = player_info.icon,
        old_table_gid = this_table_gid,
        login_ip = player_info.login_ip,
        ip_limit = roomdata.ip_limit or false,
    }   

    local ok = R().newmatchsvr(1):call('.table_mgr','match_player',user_data)
    if not ok then
        errlog(uid,'REQ_GAME_CHANGE failed to match player')
    end
   
    return true
end

--[[
    玩家请求离开房间
]]
function handler.REQ_LEAVE(uid,msg,game_session)
    if table_players[uid] ~= game_session then
        errlog(uid,'invalid status',table_players[uid],game_session)
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_LEAVE',{result = error_code.PERMISSION_DENIDE})
        return false
    end

    local player_info = player_info_list[uid]
    if not player_info then
        dbglog(uid,'handler.REQ_LEAVE player_info is nil')
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_LEAVE',{result = error_code.PERMISSION_DENIDE})
        return false
    end

    local pos = player_info.position

    --检查是否可以离开操作
    if curr_zjh_instance then
        --锁住操作了就不让玩家站起
        if curr_zjh_instance:get_operate_lock(uid) then
            dbglog("handler.REQ_LEAVE error player is have operate lock", uid)
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_LEAVE',{result = error_code.ERROR_IN_OPERATE_LOCK})
            return false
        end

        --离开期间不能弃牌
        if curr_zjh_instance:get_operate_delay_time() then
            dbglog("REQ_LEAVE error because player in operate delay time")
            return false
        end

        -- if curr_zjh_instance:player_isvalid(uid) and player_info.position then
        --     send_to_gateway(uid,game_session,'zhajinhua.RSP_LEAVE',{result = error_code.RSP_SUCESS})
        --     return true
        -- end
    end

    local robot = is_robot(uid)
    leave(uid)

    --leave_round(uid)

    --有位置的更新一下桌子信息
    -- if pos then
    --     notify_matchsvr_table_stats()
    -- end
    if not robot then
        local init_coins = player_info.init_coins or 0
        R().hallsvr({key=uid}):send('.msg_handler', 'check_lucky_tigger',uid,self_game_type,init_coins)
    end
    send_to_gateway(uid,game_session,'zhajinhua.RSP_LEAVE',{result = error_code.RSP_SUCESS})

    -- watch_session(game_session,uid,false)

    -- skynet.send('.table_mgr','lua','leave',uid)

    return true
end

function handler.REQ_USE_MAGIC_PICTURE(uid,msg,game_session)
    local src_player_info = player_info_list[uid]
    if not src_player_info then
        errlog(uid,"REQ_USE_MAGIC_PICTURE failed you are not a src_player_info")
        return false
    end

    if not src_player_info.position then
        send_to_gateway(uid,table_players[uid],'table.RSP_USE_MAGIC_PICTURE',{result = error_code.USE_ITEM_NEED_POSTION})
        return false
    end

    local dst_player_info = player_info_list[msg.dst_id]
    if not dst_player_info then
        errlog(msg.dst_id,"REQ_USE_MAGIC_PICTURE failed you are not a dst_player_info")
        return false
    end

    if not dst_player_info.position then
        errlog(uid,"REQ_USE_MAGIC_PICTURE not have position")
        return false
    end

    -- local ret = reduce_coins(uid,constant.USE_MAGIC_PICTURE_COIN,reason.USE_MAGIC_PICTRUE,get_extra_bill_info(uid))
    -- if not ret then
    --     send_to_gateway(uid,table_players[uid],'table.RSP_USE_MAGIC_PICTURE',{result = error_code.GOLD_IS_NOT_ENOUGH})
    --     return false
    -- end

    -- src_player_info.coins = ret.curr_coins
    send_to_gateway(uid,table_players[uid],'table.RSP_USE_MAGIC_PICTURE',{result = error_code.RSP_SUCESS})

    notify_all('table.NTF_USE_MAGIC_PICTURE',{src_id = uid, dst_id = msg.dst_id, picture_id = msg.picture_id})
    return true
end

function handler.REQ_AUTO_BET(uid,msg,game_session)
    local player_info = player_info_list[uid]
    if not player_info then
        errlog(uid,"REQ_USE_MAGIC_PICTURE failed you are not a player_info")
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_AUTO_BET',{result = error_code.PLAYER_HAS_NO_TABLE})
        return false
    end

    if not player_info.position then
        errlog(uid,"REQ_USE_MAGIC_PICTURE not have position")
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_AUTO_BET',{result = error_code.PLAYER_HAS_NO_TABLE})
        return false
    end

    if not curr_zjh_instance then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_AUTO_BET',{result = error_code.GAME_NOT_START})
        return false
    end

    curr_zjh_instance:set_auto_bet(uid,msg.is_auto)

    send_to_gateway(uid,game_session,'zhajinhua.RSP_AUTO_BET',{is_auto = msg.is_auto})

    send_self_operate_status(uid)

    return true
end

local function update_player_coins(uid, coins)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.coins = coins
    else
        errlog(string_format("uid(%d) coins(%d) player info not exist", uid, coins))
    end
end

local function check_have_enough_coins(uid,coins)
    local player_info = player_info_list[uid]
    if not player_info or player_info.coins < coins then
        return false
    end
    return true
end

local function caishen_coins(uid, coins, award_coins, ...)
    local robot = is_robot(uid)
    local ok, succ, ret = R().basesvr({ key = uid }):call(".msg_handler", "caishen_coins", uid, coins, award_coins, {is_robot=robot},get_extra_bill_info(uid))
    if not ok then
        errlog(string_format("uid(%d) call basesvr caishen_coins coins error", uid))
        return false
    end
    if not succ then
        errlog(string_format("uid(%d) basesvr caishen_coins coins succ == false error", uid))
        return false
    end

    --update_player_coins(uid, ret.curr)
    return ret
end

local function pay_caishen_coins(uid,coins)
    local caishenjiadao_store = global_configs.caishenjiadao_store
    local fee_rate = caishenjiadao_store.fee_rate
    local sysback_coins = math_floor((coins *fee_rate) / 10000)
    local base_coins = coins - sysback_coins
    local curr_coins
    local ret_coins = system_store.check_caishen_store_result(self_table_type,uid,coins)
    local player_info = player_info_list[uid]
    player_info.all_bet = player_info.all_bet + coins
    local produce = 0
    local win_lose = 0
    if ret_coins then
        print("add coins",ret_coins)
        curr_coins = caishen_coins(uid,coins,ret_coins)
        if not curr_coins then
            errlog("reduce coins failed",ret )
            return error_code.NOT_ENOUGH_COINS
        end
        sendLoseWinToFriendServer(coins - ret_coins)
        --改变财神库存
        R().exdbsvr(1):send('.caishen_mgr','push_data_pool',self_table_type,uid,base_coins,sysback_coins)
        R().exdbsvr(1):send('.caishen_mgr','sub_caishen_base',self_table_type,uid,ret_coins)
        player_info.all_win_lose = player_info.all_win_lose - coins + ret_coins
        player_info.all_produce = player_info.all_produce + ret_coins
        produce = ret_coins       
        win_lose =  - coins + ret_coins  
    else
        local ret = reduce_coins(uid, coins, reason.OPEN_CAISHEN)
        if not ret then
            errlog("reduce coins failed",ret )
            return error_code.NOT_ENOUGH_COINS
        end
        sendLoseWinToFriendServer(coins)
        --改变财神库存
        R().exdbsvr(1):send('.caishen_mgr','push_data_pool',self_table_type,uid,base_coins,sysback_coins)
        curr_coins = ret.curr_coins
        player_info.all_win_lose = player_info.all_win_lose - coins        
        win_lose =  - coins  
    end

    local uid = uid
    local bet_coins = coins
    local produce = produce
    local win_lose = win_lose
    local free = 0
    expand.sendSummary(self_table_type, uid, bet_coins, produce, win_lose, free)

    utils.notify_money_changed(uid,{coins = curr_coins})
    notify_all("table.NTF_MONEY_CHANGED", { chged_list = { { uid = uid, coins = curr_coins } } })
    
    update_player_coins(uid, curr_coins)
    caishen_coins_map[uid] = nil
    return error_code.RSP_SUCESS,ret_coins    
end

function handler.REQ_OPEN_CAISHEN(uid,msg)
    local coins = msg.coins
    --[[if not caishen_coins_map[uid] or caishen_coins_map[uid] ~= coins then
        errlog("put coins error",uid,caishen_coins_map[uid])
        return
    end]]
    if not caishen_coins_map[uid] or coins ~= caishen_coins_map[uid] then
        errlog("your param is error",uid,coins)
        send_to_gateway(uid,table_players[uid],'table.RSP_OPEN_CAISHEN',{result = error_code.INPUT_ERROR})
        return false
    end

    if not check_have_enough_coins(uid,coins) then
        errlog("you have not enough coins",uid)
        send_to_gateway(uid,table_players[uid],'table.RSP_OPEN_CAISHEN',{result = error_code.NOT_ENOUGH_COINS})
        return false
    end
    -- local system_win_lose = 0
    local res,ret_coins = pay_caishen_coins(uid,coins)
    if res == error_code.RSP_SUCESS then
        send_to_gateway(uid,table_players[uid],'table.RSP_OPEN_CAISHEN',{result = res,award_coins = ret_coins})
    else
        send_to_gateway(uid,table_players[uid],'table.RSP_OPEN_CAISHEN',{result = res})
    end
end

local function copy_table(t)
    local ret = {}
    for k,v in pairs(t) do
        ret[k] = v
    end
    return ret
end

function handler.REQ_RECORD_LIST(uid,msg,game_session)
    print("=============REQ_RECORD_LIST",game_session,tostring_r(op_record_list))
    local rsp_record_list = {}
    for round,op_list in pairs(op_record_list) do
        local record_info = {}
        if round == curr_round then
            record_info.round_type = ROUND_TYPE_CURR
        else
            record_info.round_type = ROUND_TYPE_LAST
        end
        record_info.op_list = copy_table(op_list)
        table_insert(rsp_record_list,record_info)
    end
    table_sort(rsp_record_list,function(a,b) return a.round_type < b.round_type end)
    print_r(rsp_record_list)
    send_to_gateway(uid,game_session,'zhajinhua.RSP_RECORD_LIST',{record_list = rsp_record_list})

    return true
end

function handler.REQ_PERSONAL_INFO(uid,msg,game_session)
    local player_info = player_info_list[msg.uid]
    local ret = {}
    if player_info then
        local personal_info = {
            uid = player_info.uid,
            name = player_info.name,
            sex = player_info.sex,
            icon = player_info.icon,
            coins = player_info.coins,
            is_self = false,
            vip_level = player_info.vip_level or 0,
            icon_border = player_info.icon_border,
        }
        ret.personal_info = personal_info
        ret.is_set_down = player_info.position and true or false
        send_to_gateway(uid,game_session,'table.RSP_PERSONAL_INFO',ret)
    else
        send_to_gateway(uid,game_session,'table.RSP_PERSONAL_INFO',{result = error_code.NO_SUCH_PLAYER})
    end
    return true
end

-- 掉线回调接口
function internal.disconnect(uid,game_session)
    dbglog(uid,'disconnect...',table_players[uid],game_session)
    if table_players[uid] ~= game_session then
        errlog(uid,'invalid status',table_players[uid],game_session)
        return
    end

    local ret = leave(uid,0)
    dbglog(uid,'disconnect...',ret)
    return true
end

function internal.stop_server()
    stopping_server = true
end

-- 关服回调接口
function internal.close_server()
    closing_server = true
end

-- 客户端其请求进入房间
function internal.enter(uid,game_session,msg)
    local ok,r = enter(uid,game_session,msg)
    if not ok then
        send_to_gateway(uid,game_session,'table.RSP_ENTER',{result = r})
        return false
    end
  
    r.result = error_code.RSP_SUCESS
    send_to_gateway(uid,game_session,'table.RSP_ENTER',r)

    notify_player_enter(uid)
    trigger_event('on_use_picture',uid,global_configs.robot_picture.robot_enter,true)
    --跟网关agent绑定seesion监控 网关有关闭事件进行通知
    watch_session(game_session,uid,true)
    
    return true
end

--function internal.req_table_info(uid,game_session)
--    local enter_info = {}
--    enter_info.ftable_info = get_table_conf()
--    enter_info.player_info_list = get_player_info_list()
--    if curr_zjh_instance then
--        enter_info.game_status = curr_zjh_instance:get_game_status(uid)
--    end

--    local rsp = {}
--    rsp.zhajinhua_enter_info = enter_info
--    rsp.result = error_code.RSP_SUCESS
--    send_to_gateway(uid,game_session,'table.RSP_TABLE_INFO',r)
--    notify_event_status(uid)
--    return true
--end

-- 延长关房间时间
function internal.touch(key)
    if recycling_table_start_time then
        recycling_table_start_time = recycling_table_start_time + 10
    end

    return self_table_type
end

-- 服务开启设置房间参数
function internal.start(conf)
    tablesvr_id = tonumber(skynet.getenv "server_id")
    self_table_id = conf.table_id
    self_table_type = conf.table_type
    this_table_gid = conf.table_gid
    self_game_type = conf.game_type
    curr_round = 0
    local table_conf = conf.table_conf

    dbglog(string.format('table<%d>,type(%d),conf(%s) got start',
                         self_table_id,self_table_type,tostring_r(table_conf)))

    self_table_pattern = table_conf.table_pattern

    return true
end

function internal.exit()
    skynet.exit()
end

--通知桌子金钱发现改变
function internal.update_coins_on_table(uid,amount,safe_box)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.coins = player_info.coins + amount
        if curr_zjh_instance then
            local next_player_id = curr_zjh_instance:get_next_player_uid()
            if next_player_id == uid then
                --金钱发生改变要通知玩家的按钮状态也发现变化
                local buttons_status = curr_zjh_instance:get_buttons_status(uid,player_info.coins,is_robot(uid),player_info_list)
                send_to_gateway(uid,table_players[uid],'zhajinhua.NTF_PLAYER_OPERATE_STATUS',{buttons_status = buttons_status})

            end
        end

        local chged_list = {}
        table_insert(chged_list,{uid=uid,coins=player_info.coins})
        if player_info.position then
            notify_all('table.NTF_MONEY_CHANGED',{chged_list=chged_list})
        else
            send_to_gateway(uid,table_players[uid],'table.NTF_MONEY_CHANGED',{chged_list = chged_list})
        end
        if safe_box then
            player_info.safe_box = safe_box
        end
    end
end

function internal.get_ftable_info()
    local table_data = {}
    local icon_list = {}
    for _,data in pairs(player_info_list) do
        print_r(data)
        table_insert(icon_list,data.icon)
    end
    table_data.icons = icon_list
    return table_data
end

function internal.get_game_type()
    return self_game_type,self_table_type
end

local function get_non_robot_players_num()
    local player_num = 0

    for _,uid in pairs(ordered_players) do
        if not is_robot(uid) then
            player_num = player_num + 1
        end        
    end

    return player_num    
end

function internal.get_user_playing_info()
    local playing_info = {}
    playing_info.game_type = self_game_type
    playing_info.table_type = self_table_type
    playing_info.total = get_non_robot_players_num()

    return playing_info
end

--在线玩家概况数据
function internal.get_summary_online()
    local res = {}
    for uid, player in pairs(player_info_list) do 
        if not is_robot(uid) then 
            table_insert(res, {
                uid = uid, 
                all_bet = player.all_bet, --总投注
                all_win_lose = player.all_win_lose, --输赢
                all_free = player.all_free, --台费
                all_produce = player.all_win_lose + player.all_bet + player.all_free, --总产出
            })
        end
    end
    return res
end














--=================================table protocols=================
local function update_player_heartbeat(uid)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.last_ping_time = util.get_now_time()
    end
end

local function get_msg_module_name(msgid)
    local m = msgdef.id_to_name[msgid]
    if not m then return end
    return m[1],m[2] --[1]->module,[2]->name
end

function dispatch_client_message(game_session,uid,msg,size)
    local _,msgid,pbmsg,pbsize = proxypack.unpack_client_message(msg,size)
    local module,name = get_msg_module_name(msgid)

    if not module or not name then
        print('invalid msgid',msgid,module,name)
        return
    end

    local pbname = module .. '.' .. name
    local req_msg = pb.decode(pbname,pbmsg,pbsize)

    if not req_msg then
        errlog('------------unknown request-----------',pbname)
        return
    end

    dbglog(string.format('[%s]>>>>>player[%s] got a request[%s] content(%s)',
        skynet.address(skynet.self()),tostring(uid),pbname,tostring_r(req_msg)))

    local f = handler[name]
    if not f then
        errlog('unknown action',pbname)
        return
    end

    local ret = f(uid,req_msg,game_session)
    if not ret then
        errlog(string.format('failed to handle requrest(%s.%s)',module,name))
    end

    update_player_heartbeat(uid)
end

local function dispatch(_,_,game_session,uid,data)
    local msg,size = proxypack.pack_raw(data)
    local ok,errmsg = xpcall(dispatch_client_message,debug.traceback,game_session,uid,msg,size)
    skynet.trash(msg,size)  --这里需要保证内存被释放
    if not ok then 
        errlog(errmsg)
    end
end


function handle_lua_req(session,source,action,...)
    --dbglog('internal request',action,...)
    local f = internal[action]
    if f then
        skynet.retpack(f(...))
    else
        handler[action](...)
    end
end

function start()
    skynet.info_func(
        function() 
            if curr_zjh_instance then
                local next_player_id = curr_zjh_instance:get_next_player_uid()
                local player_info = player_info_list[next_player_id]
                if player_info then
                    return dbglog(tostring_r(curr_zjh_instance:get_game_status(next_player_id,player_info.coins,is_robot(next_player_id),player_info_list)))
                end
            end
        end
    )

    skynet.register_protocol {
        name = "client",
        id = skynet.PTYPE_CLIENT,
        unpack = skynet.unpack,
        dispatch = dispatch
    }

    skynet.start(function()
        skynet.dispatch("lua",function(session,source,action,...)
            handle_lua_req(session,source,action,...)
        end)
        load_config()
    end)
end

return _ENV
